Това е класическо препятствие, с което повечето MySQL програмисти се сблъскват.
- Имате колона
ticket_id
това е аргументът наGROUP BY
. Отделни стойности в тази колона определят групите. - Имате колона
incoming_time
това е аргументът наMAX()
. Най-голямата стойност в тази колона над редовете във всяка група се връща като стойността наMAX()
. - Имате всички други колони от статия в таблицата. Върнатите стойности за тези колони са произволни, а не от същия ред, където
MAX()
се появява стойност.
Базата данни не може да заключи, че искате стойности от същия ред, където се появява максималната стойност.
Помислете за следните случаи:
-
Има няколко реда, където се появява една и съща максимална стойност. Кой ред трябва да се използва за показване на колоните на
article.*
? -
Пишете заявка, която връща и двата
MIN()
иMAX()
. Това е законно, но кой ред трябва даarticle.*
показване?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
-
Използвате агрегатна функция като
AVG()
илиSUM()
, където нито един ред няма тази стойност. Как базата данни да отгатне кой ред да покаже?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
В повечето марки бази данни -- както и в самия SQL стандарт -- вие не сте разрешени да напишете запитване като това, поради неяснотата. Не можете да включите колона в списъка за избор, която не е вътре в агрегатна функция или е наименувана в GROUP BY
клауза.
MySQL е по-разрешителен. Позволява ви да правите това и оставя на вас да пишете заявки без двусмисленост. Ако имате неяснота, той избира стойности от реда, който физически е първи в групата (но това зависи от механизма за съхранение).
За какво си струва, SQLite също има това поведение, но избира последното ред в групата, за да разрешите неяснотата. Давай фигурирай. Ако SQL стандартът не казва какво да се прави, това зависи от реализацията на доставчика.
Ето една заявка, която може да реши проблема ви вместо вас:
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;
С други думи, потърсете ред (a1
), за който няма друг ред (a2
) със същия ticket_id
и по-голямо incoming_time
. Ако няма по-голямо incoming_time
е намерен, LEFT OUTER JOIN връща NULL вместо съвпадение.