Toto je klasická překážka, na kterou naráží většina programátorů MySQL.
- Máte sloupec
ticket_id
to je argument proGROUP BY
. Odlišné hodnoty v tomto sloupci definují skupiny. - Máte sloupec
incoming_time
to je argument proMAX()
. Největší hodnota v tomto sloupci přes řádky v každé skupině je vrácena jako hodnotaMAX()
. - Máte všechny ostatní sloupce článku tabulky. Hodnoty vrácené pro tyto sloupce jsou libovolné, nikoli ze stejného řádku, kde je
MAX()
dojde k hodnotě.
Databáze nemůže odvodit, že chcete hodnoty ze stejného řádku, kde se vyskytuje maximální hodnota.
Přemýšlejte o následujících případech:
-
Existuje více řádků, kde se vyskytuje stejná maximální hodnota. Který řádek by měl být použit k zobrazení sloupců
article.*
? -
Napíšete dotaz, který vrátí obě
MIN()
aMAX()
. To je legální, ale který řádek by mělarticle.*
show?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
-
Používáte agregační funkci, jako je
AVG()
neboSUM()
, kde tuto hodnotu nemá žádný řádek. Jak má databáze odhadnout, který řádek má zobrazit?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
Ve většině značek databází – stejně jako v samotném standardu SQL – nejste povoleni napsat dotaz, jako je tento, kvůli nejednoznačnosti. Do výběrového seznamu nemůžete zahrnout žádný sloupec, který není v agregační funkci nebo není pojmenován v GROUP BY
doložka.
MySQL je tolerantnější. Umožňuje vám to a nechává na vás, abyste dotazy napsali bez dvojznačnosti. Pokud máte nejasnosti, vybere hodnoty z řádku, který je fyzicky první ve skupině (ale to záleží na úložišti).
Za co to stojí, SQLite má také toto chování, ale volí poslední řádek ve skupině, aby se vyřešila nejednoznačnost. Jdi zjistit. Pokud standard SQL neříká, co dělat, je to na implementaci dodavatele.
Zde je dotaz, který vám může vyřešit váš problém:
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;
Jinými slovy, vyhledejte řádek (a1
), pro který neexistuje žádný další řádek (a2
) se stejným ticket_id
a větší incoming_time
. Pokud není větší incoming_time
je nalezen, LEFT OUTER JOIN vrátí NULL místo shody.