Quiero poder seleccionar un montón de filas de una tabla de correos electrónicos y agruparlas por remitente. Mi consulta se ve así:
SELECT
`timestamp`, `fromEmail`, `subject`
FROM `incomingEmails`
GROUP BY LOWER(`fromEmail`)
ORDER BY `timestamp` DESC
La consulta casi funciona como yo quiero: selecciona registros agrupados por correo electrónico. El problema es que el asunto y la marca de tiempo no se corresponden con el registro más reciente de una dirección de correo electrónico en particular.
Por ejemplo, podría devolver:
fromEmail: john@example.com, subject: hello
fromEmail: mark@example.com, subject: welcome
Cuando los registros en 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 el tema de la "pregunta de programación" es el más reciente, ¿cómo puedo hacer que MySQL seleccione ese registro al agrupar los correos electrónicos?
fuente
As of 5.7.5 ONLY_FULL_GROUP_BY is enabled by default, i.e. it's impossible to use non-aggregate columns.
El modo SQL se puede cambiar durante el tiempo de ejecución sin privilegios de administrador, por lo que es muy fácil deshabilitar ONLY_FULL_GROUP_BY. Por ejemplo:SET SESSION sql_mode = '';
. Demostración: db-fiddle.com/f/esww483qFQXbXzJmkHZ8VT/3Aquí hay un enfoque:
Básicamente, se une a la tabla sobre sí misma, buscando filas posteriores. En la cláusula where, indica que no puede haber filas posteriores. Esto le da solo la última fila.
Si puede haber varios correos electrónicos con la misma marca de tiempo, esta consulta debería perfeccionarse. Si hay una columna de ID incremental en la tabla de correo electrónico, cambie JOIN como:
fuente
textID
era ambiguo = /LEFT JOIN
criteriosAND next.timestamp <= UNIX_TIMESTAMP()
Como ya se señaló en una respuesta, la respuesta actual es incorrecta, porque GROUP BY selecciona arbitrariamente el registro de la ventana.
Si uno está usando MySQL 5.6 o MySQL 5.7 con
ONLY_FULL_GROUP_BY
, la consulta correcta (determinista) es:Para que la consulta se ejecute de manera eficiente, se requiere una indexación adecuada.
Tenga en cuenta que, por motivos de simplificación, eliminé el
LOWER()
, que en la mayoría de los casos no se utilizará.fuente
order by
en la subselección en las otras respuestas, no tiene ningún efecto.Haga un GROUP BY después de ORDER BY envolviendo su consulta con GROUP BY de esta manera:
fuente
time
, o el más nuevotime
, o al azar?time DESC
y luego el grupo por toma la primera (la última).Según el estándar SQL, no puede usar columnas no agregadas en la lista de selección. MySQL permite tal uso (a menos que se use el modo ONLY_FULL_GROUP_BY) pero el resultado no es predecible.
ONLY_FULL_GROUP_BY
Primero debe seleccionar desde Correo electrónico, MIN (lectura) y luego, con la segunda consulta (o subconsulta) - Asunto.
fuente
Luché con estos dos enfoques para consultas más complejas que las que se muestran, porque el enfoque de subconsultas era terriblemente ineficiente sin importar los índices que puse, y porque no pude obtener la autounión externa a través de Hibernate
La mejor (y más fácil) forma de hacer esto es agrupar por algo que esté construido para contener una concatenación de los campos que necesita y luego extraerlos usando expresiones en la cláusula SELECT. Si necesita hacer un MAX () asegúrese de que el campo sobre el que desea MAX () esté siempre en el extremo más significativo de la entidad concatenada.
La clave para entender esto es que la consulta solo puede tener sentido si estos otros campos son invariantes para cualquier entidad que satisfaga el Max (), por lo que en términos del tipo, las otras partes de la concatenación pueden ignorarse. 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 puede obtener un evento de inserción / actualización (como un disparador) para precalcular la concatenación de los campos, puede indexarlo y la consulta será tan rápida como si el grupo por estuviera sobre el campo que realmente deseaba MAX ( ). Incluso puede usarlo para obtener el máximo de múltiples campos. Lo uso para hacer consultas en árboles multidimensionales expresados como conjuntos anidados.
fuente