Pregunta

Quiero ser capaz de seleccionar un grupo de filas de una tabla de correos electrónicos y agruparlos por la del emisor. Mi consulta es el siguiente:

SELECT 
    `timestamp`, `fromEmail`, `subject`
FROM `incomingEmails` 
GROUP BY LOWER(`fromEmail`) 
ORDER BY `timestamp` DESC

La consulta casi funciona como yo quiero que - se selecciona registros agrupados por e-mail. El problema es que el sujeto y el sello de tiempo no se corresponden con el registro más reciente para una dirección de correo electrónico en particular.

Por ejemplo, podría volver:

fromEmail: john@example.com, subject: hello
fromEmail: mark@example.com, subject: welcome

Cuando los registros de la base de datos son:

fromEmail: john@example.com, subject: hello
fromEmail: john@example.com, subject: programming question
fromEmail: mark@example.com, subject: welcome

Si la "cuestión de programación" sujeto es la más reciente, ¿cómo puedo obtener MySQL para seleccionar ese registro al agrupar los correos electrónicos?

¿Fue útil?

Solución

Una solución sencilla es envolver la consulta en una subselección con la declaración ORDEN primero y aplicando el GROUP BY después

SELECT * FROM ( 
    SELECT `timestamp`, `fromEmail`, `subject`
    FROM `incomingEmails` 
    ORDER BY `timestamp` DESC
) AS tmp_table GROUP BY LOWER(`fromEmail`)

Esto es similar al uso de la unión, pero parece mucho más agradable.

Uso de columnas no agregados en un SELECT con una cláusula GROUP BY no es estándar. MySQL generalmente devolver los valores de la primera fila se encuentra y desechar el resto. Cualquier cláusulas ORDER BY sólo se aplicará al valor de columna devuelta, no a los descartados.

ACTUALIZACIÓN IMPORTANTE Selección de columnas no agregados utilizados para funcionar en la práctica, pero no debe confiarse en ella. Por el MySQL documentación "esto es útil principalmente cuando todos los valores en cada columna no agregada que no se citan en el GROUP BY son los mismos para cada grupo. el servidor es libre de elegir cualquier valor de cada grupo, por lo que a menos que sean el mismo, la valores elegidos son indeterminados ".

A partir del 5.6.21 he notado problemas con el GROUP BY en la tabla temporal revertir el ORDER BY clasificación.

A partir de 5.7.5 ONLY_FULL_GROUP_BY está activado por defecto, es decir, es imposible utilizar las columnas no agregadas.

Vea http://www.cafewebmaster.com/mysql-order-sort-group https://dev.mysql.com/doc/refman /5.6/en/group-by-handling.html https://dev.mysql.com/doc/refman /5.7/en/group-by-handling.html

Otros consejos

Esto es uno de los enfoques:

SELECT cur.textID, cur.fromEmail, cur.subject, 
     cur.timestamp, cur.read
FROM incomingEmails cur
LEFT JOIN incomingEmails next
    on cur.fromEmail = next.fromEmail
    and cur.timestamp < next.timestamp
WHERE next.timestamp is null
and cur.toUserID = '$userID' 
ORDER BY LOWER(cur.fromEmail)

Básicamente, se unen a la tabla de la misma, en busca de filas posteriores. En la cláusula donde usted afirma que no puede haber filas posteriores. Esto le da sólo la última fila.

Si no puede haber múltiples correos electrónicos con la misma marca de tiempo, esta consulta tendría refinación. Si hay una columna de ID incrementales en la tabla de correo electrónico, cambiar la junta como:

LEFT JOIN incomingEmails next
    on cur.fromEmail = next.fromEmail
    and cur.id < next.id

Hacer un GROUP BY después de que el ORDER BY envolviendo la consulta con el GRUPO POR siguiente:

SELECT t.* FROM (SELECT * FROM table ORDER BY time DESC) t GROUP BY t.from

Como se señaló en una respuesta ya, la respuesta actual es incorrecto, ya que el GROUP BY arbitrariamente selecciona el registro de la ventana.

Si uno está utilizando MySQL 5.6, o MySQL 5.7 con ONLY_FULL_GROUP_BY, la (determinista) consulta correcta es:

SELECT incomingEmails.*
  FROM (
    SELECT fromEmail, MAX(timestamp) `timestamp`
    FROM incomingEmails
    GROUP BY fromEmail
  ) filtered_incomingEmails
  JOIN incomingEmails USING (fromEmail, timestamp)
GROUP BY fromEmail, timestamp

Para que la consulta se ejecute de manera eficiente, se requiere una correcta indexación.

Tenga en cuenta que a efectos de simplificación, he quitado el LOWER(), que en la mayoría de los casos, no será utilizado.

De acuerdo con el estándar SQL no se puede utilizar columnas no agregadas en la lista de selección. MySQL permite tal uso (uless modo ONLY_FULL_GROUP_BY utiliza) pero resultado no es predecible.

ONLY_FULL_GROUP_BY

Usted debe seleccionar primero fromEmail, MIN (lectura), y luego, con la segunda consulta (o subconsulta) -. Asunto

Luché con estos dos enfoques para consultas más complejas que las que se muestran, porque el enfoque sub consulta era terriblemente ineficient no importa lo que los índices Me puse, y porque no podía conseguir el exterior autocombinación a través de hibernación

La forma mejor (y más fácil) para hacer esto es agrupar por algo que se construye para contener una concatenación de los campos que necesita y luego llevar a cabo el uso de expresiones en la cláusula SELECT. Si necesita hacer una MAX () asegurarse de que el campo que desea MAX () es más siempre al final más importante de la entidad concatenada.

La clave para entender esto es que la consulta sólo puede tener sentido si estos otros campos son invariantes para cualquier entidad que satisface la Max (), por lo que en términos de la clase de las otras piezas de la concatenación pueden ser ignorados. En él se explica cómo hacer esto en la parte inferior de este enlace. http://dev.mysql.com/doc /refman/5.0/en/group-by-hidden-columns.html

Si usted puede conseguir la mañana de inserción / evento de actualización (como un disparador) para pre-calcular la concatenación de los campos que puede indexarlo, la consulta será tan rápido como si el grupo por había terminado solo el campo que en realidad quería a MAX (). Incluso se puede utilizar para obtener el máximo de varios campos. Yo lo uso para hacer consultas en los árboles multidimensionales expresssed como conjuntos anidados.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top