Zde je pět možností, jak pomocí SQL vrátit pouze ty řádky, které mají v rámci své skupiny maximální hodnotu.
Tyto příklady fungují ve většině hlavních RDBMS, včetně MySQL, MariaDB, Oracle, PostgreSQL, SQLite a SQL Server.
Ukázková data
Předpokládejme, že máme tabulku s následujícími údaji:
SELECT * FROM Gameshow;
Výsledek:
+--------------+--------+---------+ | 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 | +--------------+--------+---------+
A předpokládejme, že chceme získat nejvyšší skóre pro každého soutěžícího.
Možnost 1
Rychlou a snadnou možností je vytvořit dotaz pomocí SQL GROUP BY
klauzule:
SELECT
Contestant,
MAX( Score ) AS MaxScore
FROM Gameshow
GROUP BY Contestant
ORDER BY Contestant;
Výsledek:
+--------------+------------+ | Contestant | MaxScore | |--------------+------------| | Faye | 85 | | Jet | 51 | | Spike | 27 | +--------------+------------+
Možnost 2
Pokud chceme zahrnout hru, kterou každý soutěžící hrál, aby získal maximální skóre, pak jedním ze způsobů, jak toho dosáhnout, je použít korelovaný dílčí dotaz, jako je tento:
SELECT
Contestant,
Game,
Score
FROM Gameshow g1
WHERE Score = ( SELECT MAX( g2.Score )
FROM Gameshow g2
WHERE g1.Contestant = g2.Contestant )
ORDER BY Contestant;
Výsledek:
+--------------+--------+---------+ | Contestant | Game | Score | |--------------+--------+---------| | Faye | 1 | 85 | | Jet | 3 | 51 | | Spike | 2 | 27 | +--------------+--------+---------+
Korelované poddotazy odkazují na jeden nebo více sloupců mimo poddotaz. Korelované poddotazy mohou být neefektivní, hlavně kvůli skutečnosti, že poddotaz se provádí opakovaně, jednou pro každý řádek, který může být vybrán vnějším dotazem. Korelované poddotazy jsou také známé jako opakující se poddotazy.
Možnost 3
Alternativně můžeme použít nekorelovaný poddotaz takto:
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;
Výsledek:
+--------------+--------+---------+ | Contestant | Game | Score | |--------------+--------+---------| | Faye | 1 | 85 | | Jet | 3 | 51 | | Spike | 2 | 27 | +--------------+--------+---------+
Nekorelované poddotazy nezávisí na vnějším dotazu pro jejich provedení. Mohou se provádět zcela nezávisle na vnějším dotazu.
V Oracle musíme odstranit AS
při deklaraci aliasů sloupců:
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;
Možnost 4
Další možností je použít LEFT JOIN
, takto:
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;
Výsledek:
+--------------+--------+---------+ | Contestant | Game | Score | |--------------+--------+---------| | Faye | 1 | 85 | | Jet | 3 | 51 | | Spike | 2 | 27 | +--------------+--------+---------+
Možnost 5
Dalším způsobem, jak načíst řádky s maximální hodnotou v daném sloupci, je použít běžný tabulkový výraz s funkcí 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;
Výsledek:
+--------------+--------+---------+ | Contestant | Game | Score | |--------------+--------+---------| | Faye | 1 | 85 | | Jet | 3 | 51 | | Spike | 2 | 27 | +--------------+--------+---------+