Jest to klasyczna przeszkoda, na którą wpada większość programistów MySQL.
- Masz kolumnę
ticket_id
to jest argumentGROUP BY
. Odrębne wartości w tej kolumnie definiują grupy. - Masz kolumnę
incoming_time
to jest argumentMAX()
. Największa wartość w tej kolumnie nad wierszami w każdej grupie jest zwracana jako wartośćMAX()
. - Masz wszystkie inne kolumny artykułu tabeli. Wartości zwracane dla tych kolumn są dowolne, nie pochodzą z tego samego wiersza, w którym znajduje się
MAX()
pojawia się wartość.
Baza danych nie może wywnioskować, że chcesz wartości z tego samego wiersza, w którym występuje wartość maksymalna.
Pomyśl o następujących przypadkach:
-
Istnieje wiele wierszy, w których występuje ta sama wartość maksymalna. Który wiersz powinien być użyty do wyświetlenia kolumn
article.*
? -
Piszesz zapytanie, które zwraca zarówno
MIN()
iMAX()
. Jest to legalne, ale który wiersz powinienarticle.*
pokazać?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
-
Używasz funkcji agregującej, takiej jak
AVG()
lubSUM()
, gdzie żaden wiersz nie ma tej wartości. W jaki sposób baza danych ma odgadnąć, który wiersz wyświetlić?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
W większości marek baz danych — a także w samym standardzie SQL — nie jest to dozwolone napisać takie zapytanie, z powodu niejednoznaczności. Na liście wyboru nie można uwzględnić żadnej kolumny, która nie znajduje się w funkcji agregującej ani nie ma nazwy w GROUP BY
klauzula.
MySQL jest bardziej liberalny. Pozwala to zrobić i pozostawia tobie pisanie zapytań bez dwuznaczności. Jeśli masz niejednoznaczność, wybiera wartości z wiersza, który jest fizycznie pierwszy w grupie (ale to zależy od silnika pamięci).
Co jest warte, SQLite również zachowuje się tak, ale wybiera ostatni wiersz w grupie, aby rozwiązać niejednoznaczność. Domyśl. Jeśli standard SQL nie mówi, co robić, zależy to od implementacji dostawcy.
Oto zapytanie, które może rozwiązać Twój problem za Ciebie:
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;
Innymi słowy, poszukaj wiersza (a1
), dla którego nie ma innego wiersza (a2
) z tym samym ticket_id
i większy incoming_time
. Jeśli nie większy incoming_time
zostanie znaleziony, LEFT OUTER JOIN zwraca NULL zamiast dopasowania.