Här är fem alternativ för att använda SQL för att endast returnera de rader som har det maximala värdet inom sin grupp.
Dessa exempel fungerar i de flesta större RDBMS, inklusive MySQL, MariaDB, Oracle, PostgreSQL, SQLite och SQL Server.
Exempeldata
Anta att vi har en tabell med följande data:
SELECT * FROM Gameshow;
Resultat:
+--------------+--------+---------+ | 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 | +--------------+--------+---------+
Och anta att vi vill få högsta poäng för varje tävlande.
Alternativ 1
Ett snabbt och enkelt alternativ är att skapa en fråga med SQL GROUP BY
klausul:
SELECT
Contestant,
MAX( Score ) AS MaxScore
FROM Gameshow
GROUP BY Contestant
ORDER BY Contestant;
Resultat:
+--------------+------------+ | Contestant | MaxScore | |--------------+------------| | Faye | 85 | | Jet | 51 | | Spike | 27 | +--------------+------------+
Alternativ 2
Om vi vill inkludera spelet som varje tävlande spelade för att få maxpoäng, så är ett sätt att göra det att använda en korrelerad underfråga så här:
SELECT
Contestant,
Game,
Score
FROM Gameshow g1
WHERE Score = ( SELECT MAX( g2.Score )
FROM Gameshow g2
WHERE g1.Contestant = g2.Contestant )
ORDER BY Contestant;
Resultat:
+--------------+--------+---------+ | Contestant | Game | Score | |--------------+--------+---------| | Faye | 1 | 85 | | Jet | 3 | 51 | | Spike | 2 | 27 | +--------------+--------+---------+
Korrelerade underfrågor hänvisar till en eller flera kolumner utanför underfrågan. Korrelerade underfrågor kan vara ineffektiva, främst på grund av att underfrågan exekveras upprepade gånger, en gång för varje rad som kan väljas av den yttre frågan. Korrelerade underfrågor kallas även upprepade underfrågor.
Alternativ 3
Vi kan alternativt använda en okorrelerad underfråga så här:
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;
Resultat:
+--------------+--------+---------+ | Contestant | Game | Score | |--------------+--------+---------| | Faye | 1 | 85 | | Jet | 3 | 51 | | Spike | 2 | 27 | +--------------+--------+---------+
Okorrelerade underfrågor beror inte på den yttre frågan för deras exekvering. De kan köras helt oberoende av den yttre frågan.
I Oracle måste vi ta bort AS
när du deklarerar kolumnaliasen:
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;
Alternativ 4
Ett annat alternativ är att använda en LEFT JOIN
, så här:
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;
Resultat:
+--------------+--------+---------+ | Contestant | Game | Score | |--------------+--------+---------| | Faye | 1 | 85 | | Jet | 3 | 51 | | Spike | 2 | 27 | +--------------+--------+---------+
Alternativ 5
Ett annat sätt att hämta rader med det maximala värdet i en given kolumn är att använda ett vanligt tabelluttryck med fönsterfunktion:
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;
Resultat:
+--------------+--------+---------+ | Contestant | Game | Score | |--------------+--------+---------| | Faye | 1 | 85 | | Jet | 3 | 51 | | Spike | 2 | 27 | +--------------+--------+---------+