Solución:
La solución correcta es:
SELECT o.*
FROM `Persons` o # 'o' from 'oldest person in group'
LEFT JOIN `Persons` b # 'b' from 'bigger age'
ON o.Group = b.Group AND o.Age < b.Age
WHERE b.Age is NULL # bigger age not found
Cómo funciona:
Coincide con cada fila de o
con todas las filas de b
teniendo el mismo valor en la columna Group
y un valor mayor en la columna Age
. Cualquier fila de o
no tener el valor máximo de su grupo en columna Age
coincidirá con una o más filas de b
.
los LEFT JOIN
hace que coincida con la persona de mayor edad del grupo (incluidas las personas que están solas en su grupo) con una fila llena de NULL
s de b
(‘sin mayor edad en el grupo’).
Utilizando INNER JOIN
hace que estas filas no coincidan y se ignoren.
los WHERE
cláusula mantiene solo las filas que tienen NULL
s en los campos extraídos de b
. Son las personas mayores de cada grupo.
Lecturas adicionales
Esta solución y muchas otras se explican en el libro. Antipatrones SQL: evitar las trampas de la programación de bases de datos
Hay una forma súper simple de hacer esto en mysql:
select *
from (select * from mytable order by `Group`, age desc, Person) x
group by `Group`
Esto funciona porque en mysql puedes no columnas agregadas no agrupadas, en cuyo caso mysql solo devuelve el primero hilera. La solución es ordenar primero los datos de modo que para cada grupo la fila que desee sea la primera, luego agrupar por las columnas para las que desea el valor.
Evita subconsultas complicadas que intentan encontrar el max()
etc., y también los problemas de devolver múltiples filas cuando hay más de una con el mismo valor máximo (como lo harían las otras respuestas)
Nota: Esto es un solo mysql solución. Todas las demás bases de datos que conozco arrojarán un error de sintaxis SQL con el mensaje “las columnas no agregadas no se enumeran en la cláusula group by” o similar. Porque esta solución usa indocumentado comportamiento, los más cautelosos pueden querer incluir una prueba para afirmar que permanece funcionando en caso de que una versión futura de MySQL cambie este comportamiento.
Actualización de la versión 5.7:
Desde la versión 5.7, el sql-mode
el entorno incluye ONLY_FULL_GROUP_BY
de forma predeterminada, por lo que para que esto funcione debe no tener esta opción (edite el archivo de opciones para que el servidor elimine esta configuración).
Puede unirse a una subconsulta que extrae el MAX(Group)
y Age
. Este método es portátil en la mayoría de RDBMS.
SELECT t1.*
FROM yourTable t1
INNER JOIN
(
SELECT `Group`, MAX(Age) AS max_age
FROM yourTable
GROUP BY `Group`
) t2
ON t1.`Group` = t2.`Group` AND t1.Age = t2.max_age;