Ecco cinque opzioni per utilizzare SQL per restituire solo le righe che hanno il valore minimo all'interno del loro gruppo.
Questi esempi funzionano nella maggior parte dei principali RDBMS, inclusi MySQL, MariaDB, Oracle, PostgreSQL, SQLite e SQL Server.
Dati campione
Supponiamo di avere una tabella con i seguenti dati:
SELECT * FROM Gameshow;
Risultato:
+--------------+--------+---------+ | 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 | +--------------+--------+---------+
E supponiamo di voler ottenere il punteggio più basso per ogni concorrente.
Opzione 1
Un'opzione facile e veloce è costruire una query con SQL GROUP BY
clausola:
SELECT
Contestant,
MIN( Score ) AS MinScore
FROM Gameshow
GROUP BY Contestant
ORDER BY Contestant;
Risultato:
+--------------+------------+ | Contestant | MinScore | |--------------+------------| | Faye | 50 | | Jet | 31 | | Spike | 15 | +--------------+------------+
Opzione 2
Se vogliamo includere il gioco a cui ogni concorrente ha giocato per ottenere il punteggio minimo, un modo per farlo è utilizzare una sottoquery correlata come questa:
SELECT
Contestant,
Game,
Score
FROM Gameshow g1
WHERE Score = ( SELECT MIN( g2.Score )
FROM Gameshow g2
WHERE g1.Contestant = g2.Contestant )
ORDER BY Contestant;
Risultato:
+--------------+--------+---------+ | Contestant | Game | Score | |--------------+--------+---------| | Faye | 2 | 50 | | Jet | 1 | 31 | | Spike | 3 | 15 | +--------------+--------+---------+
Le sottoquery correlate si riferiscono a una o più colonne dall'esterno della sottoquery. Le sottoquery correlate possono essere inefficienti, principalmente a causa del fatto che la sottoquery viene eseguita ripetutamente, una volta per ogni riga che potrebbe essere selezionata dalla query esterna. Le subquery correlate sono anche note come subquery ripetute.
Opzione 3
In alternativa possiamo utilizzare una sottoquery non correlata come questa:
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;
Risultato:
+--------------+--------+---------+ | Contestant | Game | Score | |--------------+--------+---------| | Faye | 2 | 50 | | Jet | 1 | 31 | | Spike | 3 | 15 | +--------------+--------+---------+
Le sottoquery non correlate non dipendono dalla query esterna per la loro esecuzione. Possono essere eseguiti in modo completamente indipendente dalla query esterna.
In Oracle, dobbiamo rimuovere AS
quando si dichiarano gli alias di colonna:
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;
Opzione 4
Un altro modo per recuperare le righe con il valore minimo in una determinata colonna è utilizzare un LEFT JOIN
, in questo modo:
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;
Risultato:
+--------------+--------+---------+ | Contestant | Game | Score | |--------------+--------+---------| | Faye | 2 | 50 | | Jet | 1 | 31 | | Spike | 3 | 15 | +--------------+--------+---------+
Opzione 5
Un altro modo per farlo è usare un'espressione di tabella comune con la funzione finestra:
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;
Risultato:
+--------------+--------+---------+ | Contestant | Game | Score | |--------------+--------+---------| | Faye | 2 | 50 | | Jet | 1 | 31 | | Spike | 3 | 15 | +--------------+--------+---------+