php - una - Cómo agrupar por orden DESC
¿cómo crear una entrada con galerías en wordpress? (6)
Estoy escribiendo esta respuesta porque la primera / más corta alternativa de @ Taryn en respuesta aceptada funciona solo si está seleccionando exactamente solo las columnas utilizadas en GROUP BY y MAX. El usuario que pregunta es seleccionando todas las columnas en la tabla (él usó SELECCIONAR *). Entonces, cuando agrega otra tercera columna a la tabla, el valor de esa columna en el resultado de la consulta será incorrecto. Obtendrá valores mixtos de diferentes filas de la tabla. La segunda / más alternativa de @ Taryn (utilizando la unión interna y la subconsulta) funciona pero la consulta es inútilmente complicada y es 5 veces más lenta en mi caso de uso que mi alternativa simple a continuación.
Considere las questions
mesa:
id | asker
-----------
1 | Bob
2 | Bob
3 | Marley
Consulte SELECT max(id) as id, asker FROM questions GROUP BY asker ORDER BY id DESC
devuelve lo esperado :
id | asker
-----------
3 | Marley
2 | Bob
Ahora considere otras questions
mesa:
id | asker | other
-------------------
1 | Bob | 1st
2 | Bob | 2nd
3 | Marley | 3rd
Consulte SELECT max(id) as id, asker, other FROM questions GROUP BY asker ORDER BY id DESC
devuelve inesperado :
id | asker | other
-------------------
3 | Marley | 3rd
2 | Bob | 1st
... tenga en cuenta que el valor de other
para la segunda fila del resultado es incorrecto porque id=2
proviene de la segunda fila de la tabla, pero other=1st
proviene de la primera fila de la tabla! Así es como muchos usuarios en los comentarios de las respuestas de Taryn informan que esta solución no funciona.
Una posible solución simple al seleccionar también otras columnas es usar GROUP BY
+ DESC
:
SELECT id, asker, other FROM questions GROUP BY asker DESC
id | asker | other
-------------------
3 | Marley | 3rd
2 | Bob | 2nd
(ver demostración: https://www.db-fiddle.com/f/esww483qFQXbXzJmkHZ8VT/10 )
... pero esta solución simple tiene algunas limitaciones:
- La tabla debe ser InnoDB (creo que no es un problema porque obtendrá un mejor rendimiento y también desde que MySQL> = 5.5.5 el motor de almacenamiento predeterminado / preferido se cambió de MyISAM a InnoDB)
- Debe crear el índice para la columna que se usa en GRUPO POR: así que el que
asker
en este caso (creo que no es un problema porque obtendrá un mejor rendimiento, ya que el índice es adecuado en este caso. GRUPO POR normalmente necesita la creación de la tabla tmp, pero cuando el índice está disponible (no se creará la tabla tmp, que es más rápida) - Para MySQL 5.7 y 8.0 es necesario deshabilitar el modo SQL ONLY_FULL_GROUP_BY (por ejemplo,
SET SESSION sql_mode = '''';
) o usarANY_VALUE()
en las columnas seleccionadas que no se agregan para evitar el error ER_WRONG_FIELD_WITH_GROUP. - Desafortunadamente, los desarrolladores de MySQL eliminaron el soporte de ASC / DESC dentro de GROUP BY desde MySQL 8.0 https://dev.mysql.com/worklog/task/?id=8693 pero, afortunadamente, existe una alternativa de
GROUP BY col1 ORDER BY col1 ASC/DESC
:
SELECT id, asker, other FROM questions GROUP BY asker ORDER BY asker DESC
id | asker | other
-------------------
3 | Marley | 3rd
2 | Bob | 2nd
(Ver demostración: https://www.db-fiddle.com/f/esww483qFQXbXzJmkHZ8VT/11 )
... el resultado es el mismo que el anterior con GROUP BY ... DESC
(no olvide utilizar InnoDB y crear índice).
Tengo la siguiente tabla llamada preguntas:
ID | asker
1 | Bob
2 | Bob
3 | Marley
Quiero seleccionar cada persona que pregunta solo una vez y, si hay varias personas con el mismo nombre, seleccione la que tenga el ID más alto. Por lo tanto, los resultados esperados:
ID | asker
3 | Marley
2 | Bob
Yo uso la siguiente consulta:
SELECT * FROM questions GROUP by questions.asker ORDER by questions.id DESC
Obtengo el siguiente resultado:
ID | asker
3 | Marley
1 | Bob
Así que selecciona el primer ''Bob'' que encuentra en lugar del último.
Gracias
Los demás tienen razón al usar MAX (ID) para obtener los resultados que desea. Si se está preguntando por qué su consulta no funciona, es porque ORDER BY
ocurre después de GROUP BY
.
Los registros deben agruparse utilizando GROUP BY
y MAX()
para obtener el ID máximo para cada persona que asker
.
SELECT asker, MAX(ID) ID
FROM TableName
GROUP BY asker
SALIDA
╔════════╦════╗
║ ASKER ║ ID ║
╠════════╬════╣
║ Bob ║ 2 ║
║ Marley ║ 3 ║
╚════════╩════╝
Normalmente MySQL permite agrupar solo por registros de orden ascendente. Así podemos ordenar los registros antes de agruparlos.
SELECT * FROM ( SELECT * FROM questions ORDER BY id DESC ) AS questions GROUP BY questions.asker
Para obtener cada columna:
SELECT * FROM questions
WHERE id IN
(SELECT max(id) as id, asker
FROM questions
GROUP by asker
ORDER by id DESC)
Versión mejorada de la respuesta de @bluefeet.
Si desea la última id
para cada solicitante, debe utilizar una función agregada:
SELECT max(id) as id,
asker
FROM questions
GROUP by asker
ORDER by id DESC
La razón por la que estaba obteniendo el resultado inusual es porque MySQL usa una extensión a GROUP BY
que permite que los elementos de una lista de selección no estén agregados y no estén incluidos en la cláusula GROUP BY. Sin embargo, esto puede llevar a resultados inesperados porque MySQL puede elegir los valores que se devuelven. (Ver Extensiones MySQL a GROUP BY )
De los documentos de MySQL:
MySQL extiende el uso de GROUP BY para que la lista de selección pueda hacer referencia a columnas no agregadas que no se mencionan en la cláusula GROUP BY. ... Puede utilizar esta función para obtener un mejor rendimiento al evitar la ordenación y agrupación innecesarias de columnas. Sin embargo, esto es útil principalmente cuando todos los valores en cada columna no agregada no nombrados en el GRUPO POR son iguales para cada grupo. El servidor es libre de elegir cualquier valor de cada grupo, por lo tanto, a menos que sean iguales, los valores elegidos son indeterminados. Además, la selección de valores de cada grupo no puede verse influida por la adición de una cláusula ORDER BY. La clasificación del conjunto de resultados se produce después de que se hayan elegido los valores, y ORDER BY no afecta a qué valores elige el servidor.
Ahora, si tenía otras columnas que necesita regresar de la tabla, pero no desea agregarlas a GROUP BY
debido a los resultados inconsistentes que podría obtener, entonces podría usar una subconsulta para hacerlo. ( Demo )
select
q.Id,
q.asker,
q.other -- add other columns here
from questions q
inner join
(
-- get your values from the group by
SELECT max(id) as id,
asker
FROM questions
GROUP by asker
) m
on q.id = m.id
order by q.id desc