Aqui estão cinco opções para usar o SQL para retornar apenas as linhas que têm o valor mínimo em seu grupo.
Esses exemplos funcionam na maioria dos principais RDBMSs, incluindo MySQL, MariaDB, Oracle, PostgreSQL, SQLite e SQL Server.
Dados de amostra
Suponha que temos uma tabela com os seguintes dados:
SELECT * FROM Gameshow;
Resultado:
+--------------+--------+---------+ | 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 suponha que queremos obter a pontuação mais baixa para cada concorrente.
Opção 1
Uma opção rápida e fácil é construir uma consulta com o SQL
GROUP BY
cláusula:SELECT
Contestant,
MIN( Score ) AS MinScore
FROM Gameshow
GROUP BY Contestant
ORDER BY Contestant;
Resultado:
+--------------+------------+ | Contestant | MinScore | |--------------+------------| | Faye | 50 | | Jet | 31 | | Spike | 15 | +--------------+------------+
Opção 2
Se quisermos incluir o jogo que cada competidor jogou para obter a pontuação mínima, uma maneira de fazer isso é usar uma subconsulta correlacionada como esta:
SELECT
Contestant,
Game,
Score
FROM Gameshow g1
WHERE Score = ( SELECT MIN( g2.Score )
FROM Gameshow g2
WHERE g1.Contestant = g2.Contestant )
ORDER BY Contestant;
Resultado:
+--------------+--------+---------+ | Contestant | Game | Score | |--------------+--------+---------| | Faye | 2 | 50 | | Jet | 1 | 31 | | Spike | 3 | 15 | +--------------+--------+---------+
As subconsultas correlacionadas referem-se a uma ou mais colunas de fora da subconsulta. Subconsultas correlacionadas podem ser ineficientes, principalmente devido ao fato de que a subconsulta é executada repetidamente, uma vez para cada linha que pode ser selecionada pela consulta externa. As subconsultas correlacionadas também são conhecidas como subconsultas de repetição.
Opção 3
Alternativamente, podemos usar uma subconsulta não correlacionada como esta:
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;
Resultado:
+--------------+--------+---------+ | Contestant | Game | Score | |--------------+--------+---------| | Faye | 2 | 50 | | Jet | 1 | 31 | | Spike | 3 | 15 | +--------------+--------+---------+
As subconsultas não correlacionadas não dependem da consulta externa para sua execução. Eles podem ser executados de forma totalmente independente da consulta externa.
No Oracle, precisamos remover o
AS
ao declarar os aliases da coluna: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;
Opção 4
Outra maneira de buscar linhas com o valor mínimo em uma determinada coluna é usar um
LEFT JOIN
, assim: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;
Resultado:
+--------------+--------+---------+ | Contestant | Game | Score | |--------------+--------+---------| | Faye | 2 | 50 | | Jet | 1 | 31 | | Spike | 3 | 15 | +--------------+--------+---------+
Opção 5
Outra maneira de fazer isso é usando uma expressão de tabela comum com a função de janela:
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;
Resultado:
+--------------+--------+---------+ | Contestant | Game | Score | |--------------+--------+---------| | Faye | 2 | 50 | | Jet | 1 | 31 | | Spike | 3 | 15 | +--------------+--------+---------+