Mysql
 sql >> Database >  >> RDS >> Mysql

MYSQL mostra le righe errate quando si utilizza GROUP BY

Questo è un classico ostacolo che incontra la maggior parte dei programmatori MySQL.

  • Hai una colonna ticket_id questo è l'argomento per GROUP BY . Valori distinti in questa colonna definiscono i gruppi.
  • Hai una colonna incoming_time questo è l'argomento di MAX() . Il valore massimo in questa colonna sulle righe di ciascun gruppo viene restituito come valore di MAX() .
  • Hai tutte le altre colonne dell'articolo della tabella. I valori restituiti per queste colonne sono arbitrari, non dalla stessa riga in cui MAX() valore si verifica.

Il database non può dedurre che desideri valori dalla stessa riga in cui si verifica il valore massimo.

Pensa ai seguenti casi:

  • Sono presenti più righe in cui si verifica lo stesso valore massimo. Quale riga deve essere utilizzata per mostrare le colonne di article.* ?

  • Scrivi una query che restituisce sia MIN() e il MAX() . Questo è legale, ma quale riga dovrebbe article.* spettacolo?

    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
    
  • Utilizzi una funzione aggregata come AVG() o SUM() , dove nessuna riga ha quel valore. Come fa il database a indovinare quale riga visualizzare?

    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
    

Nella maggior parte delle marche di database, così come nello stesso standard SQL, non sei autorizzato scrivere una query come questa, a causa dell'ambiguità. Non puoi includere alcuna colonna nell'elenco di selezione che non sia all'interno di una funzione di aggregazione o denominata in GROUP BY clausola.

MySQL è più permissivo. Ti consente di farlo e lascia a te il compito di scrivere query senza ambiguità. In caso di ambiguità, seleziona i valori dalla riga che è fisicamente prima nel gruppo (ma dipende dal motore di archiviazione).

Per quel che vale, anche SQLite ha questo comportamento, ma sceglie l'ultimo fila nel gruppo per risolvere l'ambiguità. Vai a capire. Se lo standard SQL non dice cosa fare, dipende dall'implementazione del fornitore.

Ecco una domanda che può risolvere il tuo problema per te:

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;

In altre parole, cerca una riga (a1 ) per cui non esiste un'altra riga (a2 ) con lo stesso ticket_id e un maggiore incoming_time . Se non è superiore a incoming_time viene trovato, il LEFT OUTER JOIN restituisce NULL invece di una corrispondenza.