sql >> Base de Datos >  >> RDS >> Mysql

MYSQL muestra filas incorrectas cuando se usa GROUP BY

Este es un obstáculo clásico con el que se topan la mayoría de los programadores de MySQL.

  • Tienes una columna ticket_id ese es el argumento para GROUP BY . Valores distintos en esta columna definen los grupos.
  • Tiene una columna incoming_time ese es el argumento de MAX() . El mayor valor de esta columna sobre las filas de cada grupo se devuelve como el valor de MAX() .
  • Tienes todas las demás columnas del artículo de la tabla. Los valores devueltos para estas columnas son arbitrarios, no de la misma fila donde MAX() se produce el valor.

La base de datos no puede inferir que desea valores de la misma fila donde se encuentra el valor máximo.

Piensa en los siguientes casos:

  • Hay varias filas donde se produce el mismo valor máximo. Qué fila debe usarse para mostrar las columnas de article.* ?

  • Escribes una consulta que devuelve tanto el MIN() y el MAX() . Esto es legal, pero qué fila debe article.* mostrar?

    SELECT article.* , MIN(article.incoming_time), MAX(article.incoming_time)
    FROM ticket, article
    WHERE ticket.id = article.ticket_id
    AND ticket.queue_id = 1
    GROUP BY article.ticket_id
    
  • Utiliza una función agregada como AVG() o SUM() , donde ninguna fila tiene ese valor. ¿Cómo adivina la base de datos qué fila mostrar?

    SELECT article.* , AVG(article.incoming_time)
    FROM ticket, article
    WHERE ticket.id = article.ticket_id
    AND ticket.queue_id = 1
    GROUP BY article.ticket_id
    

En la mayoría de las marcas de bases de datos, así como en el propio estándar SQL, no está permitido para escribir una consulta como esta, debido a la ambigüedad. No puede incluir ninguna columna en la lista de selección que no esté dentro de una función agregada o nombrada en GROUP BY cláusula.

MySQL es más permisivo. Le permite hacer esto y le deja a usted escribir consultas sin ambigüedad. Si tiene ambigüedad, selecciona valores de la fila que está físicamente primero en el grupo (pero esto depende del motor de almacenamiento).

Por lo que vale, SQLite también tiene este comportamiento, pero elige el último fila en el grupo para resolver la ambigüedad. Imagínate. Si el estándar SQL no dice qué hacer, depende de la implementación del proveedor.

Aquí hay una consulta que puede resolver su problema por usted:

SELECT a1.* , a1.incoming_time AS maxtime
FROM ticket t JOIN article a1 ON (t.id = a1.ticket_id)
LEFT OUTER JOIN article a2 ON (t.id = a2.ticket_id 
  AND a1.incoming_time < a2.incoming_time)
WHERE t.queue_id = 1
  AND a2.ticket_id IS NULL;

En otras palabras, busca una fila (a1 ) para el que no hay otra fila (a2 ) con el mismo ticket_id y un mayor incoming_time . Si no hay mayor incoming_time se encuentra, LEFT OUTER JOIN devuelve NULL en lugar de una coincidencia.