Membangun sesuai aslinya
Kueri asli Anda berada di jalur yang benar untuk mengecualikan baris yang menyinggung. Anda baru saja memiliki >
bukannya =
. Langkah rumit untuk menghitung tidak ada.
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;
Lebih pendek
Mungkin lebih cepat juga.
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;
Mirip dengan kueri @Clodoaldo
atau jawaban sebelumnya dengan penjelasan lebih lanjut
.every(rating_id = 1)
lebih sederhana dari not bool_or(rating_id > 1)
, tetapi juga mengecualikan rating < 1
- yang mungkin baik-baik saja (atau bahkan lebih baik) untuk kasus Anda.
MySQL saat ini tidak mengimplementasikan (SQL standar!) every()
. Karena Anda hanya ingin menghilangkan rating_id > 1
, ekspresi sederhana ini lebih sesuai dengan kebutuhan Anda dan berfungsi di kedua RDBMS:
HAVING max(rating_id) = 1
Terpendek
Dengan count(*)
sebagai fungsi agregat jendela dan tanpa subquery.
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;
Fungsi jendela diterapkan setelah langkah agregat. Berdasarkan ini, kita mendapatkan dua langkah agregat yang dilakukan dalam satu tingkat kueri:
- Lipat setara
(atr1_id, atr2_id)
, tidak termasuk baris denganrating_id
yang berbeda ada. - Hitung baris yang tersisa dengan fungsi jendela di seluruh rangkaian.
LIMIT 1
untuk mendapatkan satu baris (semua baris akan identik).
MySQL tidak memiliki fungsi jendela. Posgres saja.
Terpendek, belum tentu tercepat.
SQL Fiddle. (Pada hal9.2 karena hal9.3 sedang offline.)