Com base no seu original
Sua consulta original estava no caminho certo para excluir linhas ofensivas. Você acabou de ter
>
em vez de =
. O passo complicado para contar estava faltando. 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;
Curto
Provavelmente mais rápido também.
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;
Semelhante à consulta de @Clodoaldo ou esta resposta anterior com mais explicações .
every(rating_id = 1)
é mais simples que not bool_or(rating_id > 1)
, mas também exclui rating < 1
- o que provavelmente é bom (ou até melhor) para o seu caso. MySQL atualmente não implementa (SQL padrão!)
every()
. Como você deseja apenas eliminar rating_id > 1
, essa expressão simples se ajusta melhor aos seus requisitos e funciona em ambos os RDBMS:HAVING max(rating_id) = 1
O mais curto
Com
count(*)
como função de agregação de janela e sem subconsulta. 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;
As funções da janela são aplicadas depois a etapa agregada. Com base nisso, temos dois etapas agregadas feitas em um único nível de consulta:
- Fold equivalente
(atr1_id, atr2_id)
, excluindo linhas em querating_id
divergente existe. - Conte as linhas restantes com uma função de janela em todo o conjunto.
LIMIT 1
para obter uma única linha (todas as linhas seriam idênticas).O MySQL não possui funções de janela. Postgre apenas.
O mais curto, não necessariamente o mais rápido.
SQL Fiddle. (Na página 9.2 já que a página 9.3 está offline no momento.)