Pregunta

Tengo dos tablas:

article('id', 'ticket_id', 'incoming_time', 'to', 'from', 'message')
ticket('id', 'queue_id')

donde las entradas representan un hilo de correos electrónicos entre clientes y personal de apoyo, y los artículos son los mensajes individuales que componen un hilo.

Estoy tratando de encontrar el artículo con el mayor tiempo entrante (expresada como una marca de tiempo Unix) para cada ticket_id, y esta es la consulta actualmente estoy usando:

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

Por ejemplo,

:article:
id --- ticket_id --- incoming_time --- to ------- from ------- message --------
11     1             1234567           help@      client@      I need help...   
12     1             1235433           client@    help@        How can we help?
13     1             1240321           help@      client@      Want food!    
...

:ticket:
id --- queue_id
1      1
...

Sin embargo, el resultado parece ser la fila con el artículo más pequeño Identificación del lugar de lo que estoy buscando que es el artículo con el máximo de tiempo entrante.

Cualquier consejo sería muy apreciado!

¿Fue útil?

Solución

Esto es un obstáculo clásico que la mayoría de los programadores de MySQL chocan.

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

La base de datos no puede deducir que desea valores de la misma fila en la que se produce el valor máximo.

Piense en los siguientes casos:

  • Hay múltiples filas en las que se produce el mismo valor max. ¿Qué fila se debe utilizar para mostrar las columnas de article.*?

  • Usted escribe una consulta que devuelve tanto el MIN() y la MAX(). Esto es legal, pero que fila debe article.* espectáculo?

    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
    
  • Se utiliza una función de agregado como AVG() o SUM(), donde ninguna fila tiene ese valor. ¿Cómo es la base de datos de adivinar qué fila para que aparezca?

    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 la base de datos -, así como el estándar SQL en sí - que no están permitidos para escribir una consulta de este tipo, debido a la ambigüedad. No se puede incluir cualquier columna en la lista de selección que no está dentro de una función agregada o citados en la cláusula GROUP BY.

MySQL es más permisiva. Se le permite hacer esto, y lo deja a usted para escribir consultas y sin ambigüedad. Si usted tiene la ambigüedad, que selecciona los valores de la fila que está físicamente por primera vez en el grupo (pero esto es hasta el motor de almacenamiento).

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

Esta es una consulta que puede resolver su problema para 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 los que no hay otra fila (a2) con el mismo ticket_id y una mayor incoming_time. Si no se encuentra una mayor incoming_time, el LEFT OUTER JOIN devuelve NULL en lugar de un partido.

Otros consejos

SELECT a1.* FROM article a1 
JOIN 
  (SELECT MAX(a2.incoming_time) AS maxtime
   FROM article a2
   JOIN ticket ON (a2.ticketid=ticket.id)
   WHERE ticket.queue_id=1) xx
  ON (a1.incoming_time=xx.maxtime);
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top