Xây dựng trên bản gốc của bạn
Truy vấn ban đầu của bạn đã đi đúng hướng để loại trừ các hàng vi phạm. Bạn vừa có >
thay vì =
. Đã thiếu bước khó đếm.
SELECT count(*) AS ct
FROM (
SELECT 1
FROM compatibility c
WHERE rating_id = 1
AND NOT EXISTS (
SELECT 1
FROM compatibility c2
WHERE c2.rating_id > 1
AND (c2.attr1_id = c.attr1_id AND c2.attr2_id = c.attr2_id OR
c2.attr1_id = c.attr2_id AND c2.attr2_id = c.attr1_id))
GROUP BY least(attr1_id, attr2_id), greatest(attr1_id, attr2_id)
) sub;
Ngắn hơn
Có lẽ cũng nhanh hơn.
SELECT count(*) AS ct
FROM (
SELECT 1 -- selecting more columns for count only would be a waste
FROM compatibility
GROUP BY least(attr1_id, attr2_id), greatest(attr1_id, attr2_id)
HAVING every(rating_id = 1)
) sub;
Tương tự với truy vấn của @ Clodoaldo
hoặc câu trả lời trước đó kèm theo giải thích rõ hơn
.
every(rating_id = 1)
đơn giản hơn not bool_or(rating_id > 1)
, nhưng cũng loại trừ rating < 1
- điều này có thể tốt (hoặc thậm chí tốt hơn) cho trường hợp của bạn.
MySQL hiện không triển khai (SQL chuẩn!) every()
. Vì bạn chỉ muốn loại bỏ rating_id > 1
, biểu thức đơn giản này phù hợp hơn với yêu cầu của bạn và hoạt động trong cả RDBMS:
HAVING max(rating_id) = 1
Ngắn nhất
Với count(*)
dưới dạng hàm tổng hợp cửa sổ và không có truy vấn con.
SELECT count(*) OVER () AS ct
FROM compatibility
GROUP BY least(attr1_id, attr2_id), greatest(attr1_id, attr2_id)
HAVING max(rating_id) = 1
LIMIT 1;
Các chức năng của cửa sổ được áp dụng sau bước tổng hợp. Dựa trên điều này, chúng tôi nhận được hai tổng hợp các bước được thực hiện trong một cấp truy vấn:
- Gấp tương đương
(atr1_id, atr2_id)
, loại trừ các hàng córating_id
khác nhau tồn tại. - Đếm các hàng còn lại bằng chức năng cửa sổ trên toàn bộ tập hợp.
LIMIT 1
để có được một hàng duy nhất (tất cả các hàng sẽ giống nhau).
MySQL không có các chức năng cửa sổ. Postgres chỉ.
Ngắn nhất, không nhất thiết phải nhanh nhất.
SQL Fiddle. (Trên pg9.2 vì pg9.3 hiện đang ngoại tuyến.)