Zde je pět možností, jak pomocí SQL vrátit pouze ty řádky, které mají v rámci své skupiny minimá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 nejnižší skóre pro každého soutěžícího.
Možnost 1
Rychlá a snadná možnost je vytvořit dotaz pomocí SQL GROUP BY
klauzule:
SELECT
Contestant,
MIN( Score ) AS MinScore
FROM Gameshow
GROUP BY Contestant
ORDER BY Contestant;
Výsledek:
+--------------+------------+ | Contestant | MinScore | |--------------+------------| | Faye | 50 | | Jet | 31 | | Spike | 15 | +--------------+------------+
Možnost 2
Pokud chceme zahrnout hru, kterou každý soutěžící hrál, aby získal minimá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 MIN( g2.Score )
FROM Gameshow g2
WHERE g1.Contestant = g2.Contestant )
ORDER BY Contestant;
Výsledek:
+--------------+--------+---------+ | Contestant | Game | Score | |--------------+--------+---------| | Faye | 2 | 50 | | Jet | 1 | 31 | | Spike | 3 | 15 | +--------------+--------+---------+
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, MIN( 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 | 2 | 50 | | Jet | 1 | 31 | | Spike | 3 | 15 | +--------------+--------+---------+
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, MIN( 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ším způsobem, jak načíst řádky s minimální hodnotou v daném sloupci, 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 | 2 | 50 | | Jet | 1 | 31 | | Spike | 3 | 15 | +--------------+--------+---------+
Možnost 5
Dalším způsobem, jak toho dosáhnout, je použití běžného tabulkového výrazu s funkcí okna:
WITH cte AS (
SELECT Contestant, Game, Score,
RANK() OVER ( PARTITION BY Contestant
ORDER BY Score ASC
) AS r
FROM Gameshow
)
SELECT Contestant, Game, Score
FROM cte
WHERE r = 1
ORDER BY Contestant ASC;
Výsledek:
+--------------+--------+---------+ | Contestant | Game | Score | |--------------+--------+---------| | Faye | 2 | 50 | | Jet | 1 | 31 | | Spike | 3 | 15 | +--------------+--------+---------+