Aquí hay cinco opciones para usar SQL para devolver solo aquellas filas que tienen el valor mínimo dentro de su grupo.
Estos ejemplos funcionan en la mayoría de los principales RDBMS, incluidos MySQL, MariaDB, Oracle, PostgreSQL, SQLite y SQL Server.
Datos de muestra
Supongamos que tenemos una tabla con los siguientes datos:
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 | +--------------+--------+---------+
Y supongamos que queremos obtener la puntuación más baja para cada concursante.
Opción 1
Una opción rápida y fácil es construir una consulta con 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 | +--------------+------------+
Opción 2
Si queremos incluir el juego que jugó cada concursante para obtener la puntuación mínima, entonces una forma de hacerlo es usar una 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 | +--------------+--------+---------+
Las subconsultas correlacionadas se refieren a una o más columnas fuera de la subconsulta. Las subconsultas correlacionadas pueden ser ineficientes, principalmente debido al hecho de que la subconsulta se ejecuta repetidamente, una vez por cada fila que podría seleccionar la consulta externa. Las subconsultas correlacionadas también se conocen como subconsultas repetidas.
Opción 3
Alternativamente, podemos usar una subconsulta no 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 | +--------------+--------+---------+
Las subconsultas no correlacionadas no dependen de la consulta externa para su ejecución. Pueden ejecutarse de forma completamente independiente de la consulta externa.
En Oracle, necesitamos eliminar el AS
al declarar los alias de la columna:
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;
Opción 4
Otra forma de obtener filas con el valor mínimo en una columna dada es usar LEFT JOIN
, así:
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 | +--------------+--------+---------+
Opción 5
Otra forma de hacerlo es usando una expresión de tabla común con función de ventana:
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 | +--------------+--------+---------+