Oto pięć opcji użycia SQL do zwrócenia tylko tych wierszy, które mają maksymalną wartość w swojej grupie.
Te przykłady działają w większości głównych RDBMS, w tym MySQL, MariaDB, Oracle, PostgreSQL, SQLite i SQL Server.
Przykładowe dane
Załóżmy, że mamy tabelę z następującymi danymi:
SELECT * FROM Gameshow;
Wynik:
+--------------+--------+---------+ | Contestant | Game | Score | |--------------+--------+---------| | Faye | 1 | 85 | | Faye | 2 | 50 | | Faye | 3 | 63 | | Jet | 1 | 31 | | Jet | 2 | 40 | | Jet | 3 | 51 | | Spike | 1 | 25 | | Spike | 2 | 27 | | Spike | 3 | 15 | +--------------+--------+---------+
I załóżmy, że chcemy uzyskać najwyższy wynik dla każdego uczestnika.
Opcja 1
Szybkim i łatwym rozwiązaniem jest skonstruowanie zapytania za pomocą SQL GROUP BY
klauzula:
SELECT
Contestant,
MAX( Score ) AS MaxScore
FROM Gameshow
GROUP BY Contestant
ORDER BY Contestant;
Wynik:
+--------------+------------+ | Contestant | MaxScore | |--------------+------------| | Faye | 85 | | Jet | 51 | | Spike | 27 | +--------------+------------+
Opcja 2
Jeśli chcemy uwzględnić grę, w którą grał każdy zawodnik, aby uzyskać maksymalny wynik, jednym ze sposobów na to jest użycie skorelowanego podzapytania w ten sposób:
SELECT
Contestant,
Game,
Score
FROM Gameshow g1
WHERE Score = ( SELECT MAX( g2.Score )
FROM Gameshow g2
WHERE g1.Contestant = g2.Contestant )
ORDER BY Contestant;
Wynik:
+--------------+--------+---------+ | Contestant | Game | Score | |--------------+--------+---------| | Faye | 1 | 85 | | Jet | 3 | 51 | | Spike | 2 | 27 | +--------------+--------+---------+
Skorelowane podzapytania odwołują się do co najmniej jednej kolumny spoza podzapytania. Skorelowane podzapytania mogą być nieefektywne, głównie ze względu na fakt, że podzapytanie jest wykonywane wielokrotnie, raz dla każdego wiersza, który może zostać wybrany przez zapytanie zewnętrzne. Skorelowane podzapytania są również nazywane podzapytaniami powtarzającymi się.
Opcja 3
Alternatywnie możemy użyć nieskorelowanego podzapytania w ten sposób:
SELECT
g1.Contestant,
g1.Game,
g1.Score
FROM Gameshow g1
JOIN (
SELECT Contestant, MAX( Score ) AS Score
FROM Gameshow
GROUP BY Contestant ) AS g2
ON g1.Contestant = g2.Contestant AND g1.Score = g2.Score
ORDER BY Contestant ASC;
Wynik:
+--------------+--------+---------+ | Contestant | Game | Score | |--------------+--------+---------| | Faye | 1 | 85 | | Jet | 3 | 51 | | Spike | 2 | 27 | +--------------+--------+---------+
Nieskorelowane podzapytania nie zależą od zewnętrznego zapytania do ich wykonania. Mogą działać całkowicie niezależnie od zewnętrznego zapytania.
W Oracle musimy usunąć AS
podczas deklarowania aliasów kolumn:
SELECT
g1.Contestant,
g1.Game,
g1.Score
FROM Gameshow g1
JOIN (
SELECT Contestant, MAX( Score ) Score
FROM Gameshow
GROUP BY Contestant ) g2
ON g1.Contestant = g2.Contestant AND g1.Score = g2.Score
ORDER BY Contestant ASC;
Opcja 4
Inną opcją jest użycie LEFT JOIN
, tak:
SELECT
g1.Contestant,
g1.Game,
g1.Score
FROM Gameshow g1
LEFT JOIN Gameshow g2 ON
g1.Contestant = g2.Contestant AND g1.Score < g2.Score
WHERE g2.Contestant IS NULL
ORDER BY g1.Contestant ASC;
Wynik:
+--------------+--------+---------+ | Contestant | Game | Score | |--------------+--------+---------| | Faye | 1 | 85 | | Jet | 3 | 51 | | Spike | 2 | 27 | +--------------+--------+---------+
Opcja 5
Innym sposobem na pobranie wierszy z maksymalną wartością w danej kolumnie jest użycie wspólnego wyrażenia tabelowego z funkcją okna:
WITH cte AS (
SELECT Contestant, Game, Score,
RANK() OVER ( PARTITION BY Contestant
ORDER BY Score DESC
) AS r
FROM Gameshow
)
SELECT Contestant, Game, Score
FROM cte
WHERE r = 1
ORDER BY Contestant ASC;
Wynik:
+--------------+--------+---------+ | Contestant | Game | Score | |--------------+--------+---------| | Faye | 1 | 85 | | Jet | 3 | 51 | | Spike | 2 | 27 | +--------------+--------+---------+