Voortbouwend op je origineel
Uw oorspronkelijke zoekopdracht was op de goede weg om aanstootgevende rijen uit te sluiten. Je had net >
in plaats van =
. De lastige stap om te tellen ontbrak.
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;
Korter
Waarschijnlijk ook sneller.
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;
Vergelijkbaar met De vraag van @Clodoaldo
of dit eerdere antwoord met meer uitleg
.every(rating_id = 1)
is eenvoudiger dan not bool_or(rating_id > 1)
, maar sluit ook rating < 1
uit - wat waarschijnlijk goed (of zelfs beter) is voor jouw geval.
MySQL implementeert momenteel niet (standaard SQL!) every()
. Omdat je alleen rating_id > 1
wilt verwijderen , deze eenvoudige uitdrukking past beter bij uw vereisten en werkt in beide RDBMS:
HAVING max(rating_id) = 1
Kortste
Met count(*)
als vensteraggregatiefunctie en zonder 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;
Vensterfuncties worden na . toegepast de aggregatiestap. Hierop voortbouwend krijgen we twee geaggregeerde stappen gedaan op één zoekniveau:
- Equivalent
(atr1_id, atr2_id)
, met uitzondering van rijen waar afwijkenderating_id
bestaan. - Tel resterende rijen met een vensterfunctie over de hele set.
LIMIT 1
om een enkele rij te krijgen (alle rijen zouden identiek zijn).
MySQL heeft geen vensterfuncties. Postgres alleen.
Kortste, niet per se de snelste.
SQL Fiddle. (Op pg9.2 aangezien pg9.3 momenteel offline is.)