Byggar på ditt original
Din ursprungliga fråga var på rätt väg för att utesluta stötande rader. Du hade precis >
istället för =
. Det knepiga steget att räkna saknades.
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;
Kortare
Förmodligen snabbare också.
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;
Liknar @Clodoaldos fråga
eller detta tidigare svar med mer förklaring
.every(rating_id = 1)
är enklare än not bool_or(rating_id > 1)
, men utesluter också rating < 1
- vilket förmodligen är bra (eller ännu bättre) för ditt fall.
MySQL implementerar för närvarande inte (standard SQL!) every()
. Eftersom du bara vill ta bort rating_id > 1
, detta enkla uttryck passar dina krav bättre och fungerar i båda RDBMS:
HAVING max(rating_id) = 1
Kortast
Med count(*)
som fönsteraggregatfunktion och utan underfråga.
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;
Fönsterfunktioner tillämpas efter det sammanlagda steget. Med utgångspunkt i detta får vi två samla steg gjorda på en enda frågenivå:
- Vik motsvarande
(atr1_id, atr2_id)
, exklusive rader därrating_id
avviker finns. - Räkna återstående rader med en fönsterfunktion över hela uppsättningen.
LIMIT 1
för att få en enda rad (alla rader skulle vara identiska).
MySQL har inga fönsterfunktioner. Postgres bara.
Kortast, inte nödvändigtvis snabbast.
SQL-fiol. (På pg9.2 eftersom pg9.3 för närvarande är offline.)