El siguiente es el ejemplo más simple posible, aunque cualquier solución debería poder escalar a la cantidad de n resultados necesarios:
Dada una tabla como la siguiente, con columnas de persona, grupo y edad, ¿cómo obtendría las 2 personas más viejas en cada grupo? (Los lazos dentro de los grupos no deberían arrojar más resultados, sino dar los 2 primeros en orden alfabético)
+ -------- + ------- + ----- + El | Persona | Grupo | Edad | + -------- + ------- + ----- + El | Bob | 1 | 32 El | Jill 1 | 34 El | Shawn 1 | 42 | El | Jake 2 | 29 | El | Paul | 2 | 36 El | Laura | 2 | 39 + -------- + ------- + ----- +
Conjunto de resultados deseado:
+ -------- + ------- + ----- + El | Shawn 1 | 42 | El | Jill 1 | 34 El | Laura | 2 | 39 El | Paul | 2 | 36 + -------- + ------- + ----- +
NOTA: Esta pregunta se basa en una anterior: obtenga registros con el valor máximo para cada grupo de resultados SQL agrupados , para obtener una sola fila superior de cada grupo y que recibió una gran respuesta específica de MySQL de @Bohemian:
select *
from (select * from mytable order by `Group`, Age desc, Person) x
group by `Group`
Me encantaría poder construir a partir de esto, aunque no veo cómo.
Respuestas:
Aquí hay una manera de hacer esto, usando
UNION ALL
(Ver SQL Fiddle with Demo ). Esto funciona con dos grupos, si tiene más de dos grupos, deberá especificar elgroup
número y agregar consultas para cada unogroup
:Hay una variedad de formas de hacer esto, consulte este artículo para determinar la mejor ruta para su situación:
http://www.xaprb.com/blog/2006/12/07/how-to-select-the-firstleastmax-row-per-group-in-sql/
Editar:
Esto también podría funcionar para usted, genera un número de fila para cada registro. Usando un ejemplo del enlace de arriba, esto devolverá solo aquellos registros con un número de fila menor o igual a 2:
Ver demo
fuente
SELECT
(y, de hecho, a veces las evalúa fuera de orden). La clave de la solución es poner todas las asignaciones de variables en una sola expresión; Aquí hay un ejemplo: stackoverflow.com/questions/38535020/… .En otras bases de datos puedes hacer esto usando
ROW_NUMBER
. MySQL no es compatible,ROW_NUMBER
pero puede usar variables para emularlo:Véalo trabajando en línea: sqlfiddle
Editar Acabo de notar que bluefeet publicó una respuesta muy similar: +1 para él. Sin embargo, esta respuesta tiene dos pequeñas ventajas:
Así que lo dejaré aquí en caso de que pueda ayudar a alguien.
fuente
JOIN (SELECT @prev := NULL, @rn := 0) AS vars
. Tengo la idea de declarar variables vacías, pero parece extraño para MySql.Prueba esto:
MANIFESTACIÓN
fuente
a.person
.¿Qué tal usar auto-unión:
me da
La respuesta de Bill Karwin me inspiró fuertemente a Seleccionar los 10 mejores registros para cada categoría
Además, estoy usando SQLite, pero esto debería funcionar en MySQL.
Otra cosa: en lo anterior, reemplacé la
group
columna con unagroupname
columna por conveniencia.Editar :
Después del comentario del OP con respecto a los resultados de empate faltantes, incrementé la respuesta del snuffin para mostrar todos los empates. Esto significa que si los últimos son empates, se pueden devolver más de 2 filas, como se muestra a continuación:
me da
fuente
ERROR 1242 (21000): Subquery returns more than 1 row
, presumiblemente por elGROUP BY
. Cuando ejecuto laSELECT MIN
subconsulta sola, genera tres filas:34, 39, 112
y parece que el segundo valor debería ser 36, no 39.La solución Snuffin parece bastante lenta de ejecutar cuando tienes muchas filas y las soluciones Mark Byers / Rick James y Bluefeet no funcionan en mi entorno (MySQL 5.6) porque el orden por se aplica después de la ejecución de select, así que aquí hay una variante de las soluciones de Marc Byers / Rick James para solucionar este problema (con una selección imbricada adicional):
Intenté una consulta similar en una tabla que tiene 5 millones de filas y devuelve el resultado en menos de 3 segundos
fuente
LIMIT 9999999
a cualquier tabla derivada con unORDER BY
. Esto puede evitar queORDER BY
se ignore.Mira esto:
Fiddle de SQL: http://sqlfiddle.com/#!2/cdbb6/15
fuente
max(internal_version - 1)
así que menos estrés :)Si las otras respuestas no son lo suficientemente rápidas Prueba este código :
Salida:
fuente
Quería compartir esto porque pasé mucho tiempo buscando una manera fácil de implementar esto en un programa Java en el que estoy trabajando. Esto no da la salida que estás buscando, pero está cerca. La función llamada mysql
GROUP_CONCAT()
funcionó muy bien para especificar cuántos resultados devolver en cada grupo. UsarLIMIT
o alguna de las otras formas elegantes de tratar de hacer estoCOUNT
no funcionó para mí. Entonces, si está dispuesto a aceptar una salida modificada, es una gran solución. Digamos que tengo una tabla llamada 'estudiante' con identificación de estudiante, su género y gpa. Digamos que quiero superar los 5 gpas para cada género. Entonces puedo escribir la consulta asíTenga en cuenta que el parámetro '5' le dice cuántas entradas concatenar en cada fila
Y la salida se vería algo así
También puede cambiar la
ORDER BY
variable y ordenarlas de una manera diferente. Entonces, si tuviera la edad del estudiante, podría reemplazar el 'gpa desc' con 'age desc' y ¡funcionará! También puede agregar variables al grupo por declaración para obtener más columnas en la salida. Entonces, esta es solo una forma en que encontré que es bastante flexible y funciona bien si está de acuerdo con solo enumerar los resultados.fuente
En SQL Server
row_numer()
es una función poderosa que puede obtener resultados fácilmente como a continuaciónfuente
Hay una muy buena respuesta a este problema en MySQL: cómo obtener las mejores filas N por cada grupo
Según la solución en el enlace al que se hace referencia, su consulta sería como:
donde
n
esta eltop n
yyour_table
es el nombre de tu mesa.Creo que la explicación en la referencia es realmente clara. Para una referencia rápida, lo copiaré y pegaré aquí:
fuente