2012-06-12 27 views
31

Digamos que tengo una tabla llamada messages con las columnas:¿Cómo obtener el último registro de cada grupo usando GROUP BY?

id | from_id | to_id | subject | message | timestamp 

Quiero conseguir el último mensaje de cada usuario sólo, como se vería en su bandeja de entrada de Facebook antes de profundizar en el hilo real.

Esta consulta parece conseguirme próxima al resultado que necesito:

SELECT * FROM messages GROUP BY from_id 

Sin embargo la consulta me está dando el mensaje más antiguo de cada usuario y no el más nuevo.

No puedo entender esto.

+0

Incluso hay una mejor solución a este problema [aquí] (http://stackoverflow.com/questions/1313120/retrieving-the-last- record-in-each-group) –

Respuesta

74

Usted debe averiguar últimos timestamp valores de cada grupo (subconsulta), y después se une a este sub consulta a la tabla -

SELECT t1.* FROM messages t1 
    JOIN (SELECT from_id, MAX(timestamp) timestamp FROM messages GROUP BY from_id) t2 
    ON t1.from_id = t2.from_id AND t1.timestamp = t2.timestamp; 
+4

+1 ¡Un problema común pero muchas gracias por no usar la función de MySQL de permitir columnas en la selección que no están en el grupo! – GarethD

+0

¡Muchísimas gracias! Pude unir mesa adicional sin problema. Tal buen enfoque. – user1019144

+0

Esto es simplemente perfecto. – enchance

-4

Usted necesita pedirlos.

SELECT * FROM messages GROUP BY from_id ORDER BY timestamp DESC LIMIT 1

+0

seleccionar arriba (1) * .... – BumbleB2na

+0

@ BumbleB2na 'LIMIT 1 '¿A qué se refiere? – Li0liQ

+0

ahora obtendrá el último mensaje de TODOS LOS MENSAJES, necesita una condición donde – jcho360

1

Este es un problema estándar.

Tenga en cuenta que MySQL le permite omitir columnas de la cláusula GROUP BY, lo que no ocurre con SQL estándar, pero no obtiene resultados determinísticos en general cuando utiliza la facilidad MySQL.

SELECT * 
    FROM Messages AS M 
    JOIN (SELECT To_ID, From_ID, MAX(TimeStamp) AS Most_Recent 
      FROM Messages 
     WHERE To_ID = 12345678 
     GROUP BY From_ID 
     ) AS R 
    ON R.To_ID = M.To_ID AND R.From_ID = M.From_ID AND R.Most_Recent = M.TimeStamp 
WHERE M.To_ID = 12345678 

He añadido un filtro en el To_ID para que coincida con lo que es probable que tenga. La consulta funcionará sin ella, pero devolverá muchos más datos en general. No es necesario que la condición se establezca tanto en la consulta anidada como en la consulta externa (el optimizador debe presionar la condición de forma automática), pero no es dañino repetir la condición como se muestra.

+0

El último estándar de SQL le permite omitir columnas en el 'GROUP BY' e inclúyalos en la cláusula' SELECT' o 'HAVING', siempre que dependan funcionalmente de la combinación' GROUP BY' - y, por lo tanto, solo se devolverán resultados determinísticos. (MySQL no hace tal verificación, por supuesto.) –

+0

@ypercube No estoy seguro de si este es el lugar para esto, pero ¿tiene algún buen enlace para esto? No entiendo cómo seleccionar columnas que no están en el grupo podría ser determinista al depender de los elementos del grupo, la única forma en que puedo ver para que no sea determinista es mediante el uso del orden por. Sin embargo, ver ejemplos puede ayudar a aclarar las cosas. Gracias – GarethD

+0

'GROUP BY pk' sería un simple ejemplo. Mi respuesta [aquí] (http://stackoverflow.com/questions/7594865/why-does-mysql-add-a-feature-that-conflicts-with-sql-standards/7596265#7596265) tiene un enlace a (una copia de) el estándar. –

2

Sólo complementando lo que dijo Devart, el código de abajo no está ordenando de acuerdo con la pregunta: ¿

SELECT t1.* FROM messages t1 
    JOIN (SELECT from_id, MAX(timestamp) timestamp FROM messages GROUP BY from_id) t2 
    ON t1.from_id = t2.from_id AND t1.timestamp = t2.timestamp; 

El "GROUP BY" cláusula debe estar en la consulta principal, ya que necesitamos primero reordenar la "fuente" para conseguir la necesaria "agrupación" de modo:

SELECT t1.* FROM messages t1 
    JOIN (SELECT from_id, MAX(timestamp) timestamp FROM messages ORDER BY timestamp DESC) t2 
    ON t1.from_id = t2.from_id AND t1.timestamp = t2.timestamp GROUP BY t2.timestamp; 

Saludos,

12

Prueba este

SELECT * FROM messages where id in (SELECT max(id) FROM messages GROUP BY from_id) order by id desc 
+3

Si bien este código puede responder la pregunta, sería mejor incluir algún _context_, explicar _how_ works y _when_ para usarlo. Las respuestas de solo código no son útiles a largo plazo. –

+0

"SELECCIONAR max (id) FROM mensajes GROUP BY from_id" esta consulta interna, primero agrupando registros/mensajes por usuario (from_id) y luego tirando max id de registro. Luego volvemos a consultar en la tabla de mensajes para obtener solo los últimos registros/mensajes del conjunto de resultados de la consulta interna. –

+0

La solución más simple IMHO – Nowdeen

2

este retorno consulta último registro para cada form_id:

SELECT m1.* 
    FROM messages m1 LEFT JOIN messages m2 
    ON (m1.Form_id = m2.Form_id AND m1.id < m2.id) 
    WHERE m2.id IS NULL; 
+0

Honestamente, esta respuesta es subestimada. Esta fue la única solución que funcionó bien para mí ya que estoy agrupando por un campo diferente además de mi campo de incremento automático, y tengo que seleccionar la última fecha. –

+0

Esta respuesta me ayudó a hacerlo funcionar con Hibernate HQL. Ninguna de las otras respuestas funcionó, porque Hibernate admite subconsultas solo después de WHERE y SELECT. Como esta respuesta no usa ninguna subconsulta, funcionó bien. – Alex