Đây là một trở ngại kinh điển mà hầu hết các lập trình viên MySQL đều gặp phải.
- Bạn có một cột
ticket_id
đó là đối số củaGROUP BY
. Các giá trị riêng biệt trong cột này xác định các nhóm. - Bạn có một cột
incoming_time
đó là đối số củaMAX()
. Giá trị lớn nhất trong cột này trên các hàng trong mỗi nhóm được trả về dưới dạng giá trị củaMAX()
. - Bạn có tất cả các cột khác của bài viết trong bảng. Các giá trị được trả về cho các cột này là tùy ý, không phải từ cùng một hàng có
MAX()
giá trị xảy ra.
Cơ sở dữ liệu không thể suy ra rằng bạn muốn các giá trị từ cùng một hàng nơi xuất hiện giá trị lớn nhất.
Hãy suy nghĩ về các trường hợp sau:
-
Có nhiều hàng xuất hiện cùng một giá trị tối đa. Hàng nào nên được sử dụng để hiển thị các cột của bài viết
article.*
? -
Bạn viết một truy vấn trả về cả
MIN()
vàMAX()
. Điều này là hợp pháp, nhưng hàng nào nênarticle.*
hiển thị?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
-
Bạn sử dụng một hàm tổng hợp chẳng hạn như
AVG()
hoặcSUM()
, không có hàng nào có giá trị đó. Cơ sở dữ liệu làm cách nào để đoán hàng nào sẽ hiển thị?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
Trong hầu hết các thương hiệu cơ sở dữ liệu - cũng như bản thân tiêu chuẩn SQL - bạn không được phép để viết một truy vấn như thế này, vì sự không rõ ràng. Bạn không thể bao gồm bất kỳ cột nào trong danh sách chọn không nằm trong một hàm tổng hợp hoặc có tên trong GROUP BY
mệnh đề.
MySQL dễ dãi hơn. Nó cho phép bạn làm điều này và để bạn viết các truy vấn mà không bị mơ hồ. Nếu bạn không rõ ràng, nó sẽ chọn các giá trị từ hàng vật lý đầu tiên trong nhóm (nhưng điều này tùy thuộc vào công cụ lưu trữ).
Đối với những gì nó đáng giá, SQLite cũng có hành vi này, nhưng nó chọn cuối cùng hàng trong nhóm để giải quyết sự không rõ ràng. Đi tìm con số. Nếu tiêu chuẩn SQL không cho biết phải làm gì, thì tùy thuộc vào việc triển khai của nhà cung cấp.
Đây là một truy vấn có thể giải quyết vấn đề của bạn cho bạn:
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;
Nói cách khác, hãy tìm một hàng (a1
) mà không có hàng nào khác (a2
) với cùng một ticket_id
và incoming_time
lớn hơn . Nếu không có incoming_time
lớn hơn được tìm thấy, LEFT OUTER JOIN trả về NULL thay vì khớp.