Construyendo sobre su original
Su consulta original estaba en el camino correcto para excluir las filas infractoras. Acabas de tener >
en lugar de =
. Faltaba el paso complicado de contar.
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;
Más corto
Probablemente más rápido también.
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;
Similar a Consulta de @Clodoaldo
o esta respuesta anterior con más explicación
.every(rating_id = 1)
es más simple que not bool_or(rating_id > 1)
, pero también excluye rating < 1
- lo que probablemente esté bien (o incluso mejor) para su caso.
every()
. Dado que solo desea eliminar rating_id > 1
, esta simple expresión se ajusta mejor a sus requisitos y funciona en ambos RDBMS:
HAVING max(rating_id) = 1
Más corto
Con count(*)
como función agregada de ventana y sin 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;
Las funciones de ventana se aplican después el paso agregado. Partiendo de esto, obtenemos dos pasos agregados realizados en un solo nivel de consulta:
- Doblar equivalente
(atr1_id, atr2_id)
, excluyendo filas donde divergenrating_id
existir. - Cuente las filas restantes con una función de ventana en todo el conjunto.
LIMIT 1
para obtener una sola fila (todas las filas serían idénticas).
MySQL no tiene funciones de ventana. Postgres solamente.
El más corto, no necesariamente el más rápido.
SQL Fiddle. (En la página 9.2, ya que la página 9.3 está actualmente fuera de línea).