Một vài điểm quan trọng về cách sử dụng SQL:
- Bạn không thể sử dụng bí danh cột trong mệnh đề WHERE, nhưng bạn có thể sử dụng bí danh trong mệnh đề HAVING. Đó là nguyên nhân gây ra lỗi mà bạn mắc phải.
- Bạn có thể thực hiện công việc đếm của mình bằng cách sử dụng JOIN và GROUP BY tốt hơn so với bằng cách sử dụng các truy vấn con có liên quan. Nó sẽ nhanh hơn nhiều.
- Sử dụng mệnh đề HAVING để lọc các nhóm.
Đây là cách tôi viết truy vấn này:
SELECT t1.id, COUNT(t2.id) AS num_things
FROM t1 JOIN t2 USING (id)
GROUP BY t1.id
HAVING num_things = 5;
Tôi nhận thấy rằng truy vấn này có thể bỏ qua JOIN
với t1, như trong giải pháp của Charles Bretana. Nhưng tôi cho rằng bạn có thể muốn truy vấn bao gồm một số cột khác từ t1.
Re:câu hỏi trong bình luận:
Sự khác biệt là WHERE
mệnh đề được đánh giá trên các hàng, trước GROUP BY
giảm các nhóm xuống một hàng cho mỗi nhóm. HAVING
mệnh đề được đánh giá sau khi các nhóm được thành lập. Vì vậy, ví dụ:bạn không thể thay đổi COUNT()
của một nhóm bằng cách sử dụng HAVING
; bạn chỉ có thể loại trừ chính nhóm đó.
SELECT t1.id, COUNT(t2.id) as num
FROM t1 JOIN t2 USING (id)
WHERE t2.attribute = <value>
GROUP BY t1.id
HAVING num > 5;
Trong truy vấn trên, WHERE
bộ lọc cho các hàng phù hợp với một điều kiện và HAVING
bộ lọc cho các nhóm có ít nhất năm số lượng.
Điểm khiến hầu hết mọi người nhầm lẫn là khi họ không có GROUP BY
mệnh đề, vì vậy nó có vẻ như như HAVING
và WHERE
có thể hoán đổi cho nhau.
WHERE
được đánh giá trước các biểu thức trong danh sách chọn. Điều này có thể không rõ ràng vì cú pháp SQL đặt danh sách chọn lên đầu tiên. Vì vậy, bạn có thể tiết kiệm rất nhiều tính toán tốn kém bằng cách sử dụng WHERE
để hạn chế hàng.
SELECT <expensive expressions>
FROM t1
HAVING primaryKey = 1234;
Nếu bạn sử dụng truy vấn như trên, các biểu thức trong danh sách chọn được tính cho mọi hàng , chỉ để loại bỏ hầu hết các kết quả do HAVING
tình trạng. Tuy nhiên, truy vấn bên dưới chỉ tính biểu thức cho hàng đơn khớp với WHERE
điều kiện.
SELECT <expensive expressions>
FROM t1
WHERE primaryKey = 1234;
Vì vậy, tóm lại, các truy vấn được chạy bởi công cụ cơ sở dữ liệu theo một loạt các bước:
- Tạo tập hợp các hàng từ (các) bảng, bao gồm bất kỳ hàng nào được tạo bởi
JOIN
. - Đánh giá
WHERE
điều kiện so với tập hợp các hàng, lọc ra các hàng không khớp. - Tính toán các biểu thức trong danh sách chọn cho từng biểu thức trong tập hợp các hàng.
- Áp dụng bí danh cột (lưu ý đây là một bước riêng biệt, có nghĩa là bạn không thể sử dụng bí danh trong các biểu thức trong danh sách chọn).
- Thu gọn các nhóm thành một hàng cho mỗi nhóm, theo
GROUP BY
mệnh đề. - Đánh giá
HAVING
điều kiện chống lại các nhóm, lọc ra các nhóm không phù hợp. - Sắp xếp kết quả, theo
ORDER BY
mệnh đề.