sql >> Base de Datos >  >> NoSQL >> MongoDB

5 formas de seleccionar filas con el valor máximo para su grupo en SQL

Aquí hay cinco opciones para usar SQL para devolver solo aquellas filas que tienen el valor máximo 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 alta 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,
    MAX( Score ) AS MaxScore
FROM Gameshow
GROUP BY Contestant
ORDER BY Contestant;

Resultado:

+--------------+------------+
| Contestant   | MaxScore   |
|--------------+------------|
| Faye         | 85         |
| Jet          | 51         |
| Spike        | 27         |
+--------------+------------+

Opción 2

Si queremos incluir el juego que jugó cada concursante para obtener la puntuación máxima, entonces una forma de hacerlo es usar una subconsulta correlacionada como esta:

SELECT 
    Contestant,
    Game,
    Score
FROM Gameshow g1
WHERE Score = ( SELECT MAX( g2.Score )
              FROM Gameshow g2
              WHERE g1.Contestant = g2.Contestant )
ORDER BY Contestant;

Resultado:

+--------------+--------+---------+
| Contestant   | Game   | Score   |
|--------------+--------+---------|
| Faye         | 1      | 85      |
| Jet          | 3      | 51      |
| Spike        | 2      | 27      |
+--------------+--------+---------+

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, 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;

Resultado:

+--------------+--------+---------+
| Contestant   | Game   | Score   |
|--------------+--------+---------|
| Faye         | 1      | 85      |
| Jet          | 3      | 51      |
| Spike        | 2      | 27      |
+--------------+--------+---------+

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, MAX( 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 opción es usar un 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         | 1      | 85      |
| Jet          | 3      | 51      |
| Spike        | 2      | 27      |
+--------------+--------+---------+

Opción 5

Otra forma de obtener filas con el valor máximo en una columna dada es usar 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 DESC
            ) AS r
    FROM Gameshow
)
SELECT Contestant, Game, Score
FROM cte
WHERE r = 1
ORDER BY Contestant ASC;

Resultado:

+--------------+--------+---------+
| Contestant   | Game   | Score   |
|--------------+--------+---------|
| Faye         | 1      | 85      |
| Jet          | 3      | 51      |
| Spike        | 2      | 27      |
+--------------+--------+---------+