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

MYSQL viser forkerte rækker ved brug af GROUP BY

Dette er en klassisk forhindring, som de fleste MySQL-programmører støder ind i.

  • Du har en kolonne ticket_id det er argumentet til GROUP BY . Distinkte værdier i denne kolonne definerer grupperne.
  • Du har en kolonne incoming_time det er argumentet til MAX() . Den største værdi i denne kolonne over rækkerne i hver gruppe returneres som værdien af ​​MAX() .
  • Du har alle andre kolonner i tabelartikler. De returnerede værdier for disse kolonner er vilkårlige, ikke fra den samme række, hvor MAX() værdi opstår.

Databasen kan ikke udlede, at du ønsker værdier fra den samme række, hvor maks. værdien forekommer.

Tænk på følgende tilfælde:

  • Der er flere rækker, hvor den samme maks. værdi forekommer. Hvilken række skal bruges til at vise kolonnerne i article.* ?

  • Du skriver en forespørgsel, der returnerer både MIN() og MAX() . Dette er lovligt, men hvilken række skal article.* vise?

    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
    
  • Du bruger en aggregeret funktion såsom AVG() eller SUM() , hvor ingen række har den værdi. Hvordan skal databasen gætte, hvilken række der skal vises?

    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
    

I de fleste databasemærker – såvel som selve SQL-standarden – er du ikke tilladt at skrive en forespørgsel som denne på grund af tvetydigheden. Du kan ikke inkludere nogen kolonne i valglisten, der ikke er inde i en samlet funktion eller navngivet i GROUP BY klausul.

MySQL er mere eftergivende. Det lader dig gøre dette, og overlader det til dig at skrive forespørgsler uden tvetydighed. Hvis du har tvetydighed, vælger den værdier fra rækken, der fysisk er først i gruppen (men dette er op til lagermotoren).

For hvad det er værd, har SQLite også denne adfærd, men den vælger den sidste række i gruppen for at løse tvetydigheden. Gå figur. Hvis SQL-standarden ikke siger, hvad der skal gøres, er det op til leverandørens implementering.

Her er en forespørgsel, der kan løse dit problem for dig:

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;

Med andre ord, se efter en række (a1 ), som der ikke er nogen anden række for (a2 ) med samme ticket_id og en længere incoming_time . Hvis ikke længere incoming_time er fundet, returnerer LEFT OUTER JOIN NULL i stedet for et match.



  1. Hvad siger SQL-standarden om parenteser i SQL UNION/EXCEPT/INTERSECT-sætninger?

  2. Begrænsning af parallelle/samtidige downloads - Hvordan ved man, om download blev annulleret?

  3. Bedste praksis til at migrere data fra MySQL til BigQuery

  4. JSON_OBJECTAGG() Funktion i Oracle