Navazovat na svůj originál
Váš původní dotaz byl na správné cestě k vyloučení problematických řádků. Právě jste měli >
místo =
. Chyběl záludný krok k počítání.
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;
Kratší
Pravděpodobně také rychlejší.
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;
Podobné jako dotaz @Clodoaldo
nebo tuto dřívější odpověď s podrobnějším vysvětlením
.every(rating_id = 1)
je jednodušší než not bool_or(rating_id > 1)
, ale také nezahrnuje rating < 1
- což je pro váš případ pravděpodobně v pořádku (nebo ještě lepší).
MySQL aktuálně neimplementuje (standardní SQL!) every()
. Protože chcete odstranit pouze rating_id > 1
, tento jednoduchý výraz lépe vyhovuje vašim požadavkům a funguje v obou RDBMS:
HAVING max(rating_id) = 1
Nejkratší
Pomocí count(*)
jako funkci agregace oken a bez poddotazu.
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;
Funkce okna se použijí po souhrnný krok. Na základě toho dostáváme dva souhrnné kroky provedené na úrovni jednoho dotazu:
- Ekvivalent přeložení
(atr1_id, atr2_id)
, kromě řádků, kde serating_id
liší existovat. - Počítejte zbývající řádky pomocí funkce okna přes celou sadu.
LIMIT 1
získat jeden řádek (všechny řádky by byly identické).
MySQL nemá okenní funkce. Postgres pouze.
Nejkratší, ne nutně nejrychlejší.
SQL Fiddle. (Na str.9.2, protože pg9.3 je aktuálně offline.)