Detta är ett klassiskt hinder som de flesta MySQL-programmerare stöter på.
- Du har en kolumn
ticket_id
det är argumentet tillGROUP BY
. Distinkta värden i den här kolumnen definierar grupperna. - Du har en kolumn
incoming_time
det är argumentet tillMAX()
. Det största värdet i den här kolumnen över raderna i varje grupp returneras som värdetMAX()
. - Du har alla andra kolumner i tabellartiklar. Värdena som returneras för dessa kolumner är godtyckliga, inte från samma rad där
MAX()
värde uppstår.
Databasen kan inte sluta sig till att du vill ha värden från samma rad där maxvärdet förekommer.
Tänk på följande fall:
-
Det finns flera rader där samma maxvärde förekommer. Vilken rad ska användas för att visa kolumnerna i
article.*
? -
Du skriver en fråga som returnerar både
MIN()
ochMAX()
. Detta är lagligt, men vilken rad skaarticle.*
visa?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 använder en aggregerad funktion som
AVG()
ellerSUM()
, där ingen rad har det värdet. Hur kan databasen gissa vilken rad som ska visas?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 flesta märken av databas – såväl som själva SQL-standarden – är du inte tillåten att skriva en fråga som denna, på grund av oklarheten. Du kan inte inkludera någon kolumn i urvalslistan som inte finns i en aggregerad funktion eller namngiven i GROUP BY
klausul.
MySQL är mer tillåtande. Det låter dig göra detta och överlåter till dig att skriva frågor utan tvetydighet. Om du har oklarheter väljer den värden från raden som är fysiskt först i gruppen (men detta är upp till lagringsmotorn).
För vad det är värt har SQLite också detta beteende, men det väljer det sista rad i gruppen för att lösa tvetydigheten. Gissa. Om SQL-standarden inte säger vad som ska göras är det upp till leverantörens implementering.
Här är en fråga som kan lösa ditt problem åt 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 andra ord, leta efter en rad (a1
) för vilken det inte finns någon annan rad (a2
) med samma ticket_id
och en längre incoming_time
. Om ingen längre incoming_time
hittas, returnerar LEFT OUTER JOIN NULL istället för en matchning.