sqlpostgresqlaggregateboolean

EVERY en SQL: comprobar una condicion en todo el grupo

EVERY es el sinonimo estandar de BOOL_AND: true cuando la condicion se cumple en cada fila contada, NULL sobre un grupo vacio.

3 min de lecturaReferencesql · postgresql · aggregate · boolean · clickhouse

EVERY es una funcion de agregacion que reduce un grupo de valores booleanos a uno solo: devuelve true solo cuando la condicion se cumple en todas las filas contadas del grupo. Es el sinonimo estandar de BOOL_AND y es justo lo que necesitas cuando la pregunta es "cumplen todas las filas esta regla?".

Sintaxis basica

EVERY recibe una expresion booleana que se evalua por fila. El resultado es true si todas las filas contadas dieron true, y false si al menos una dio false.

SELECT dept, EVERY(salary > 0) AS all_paid
FROM employees
GROUP BY dept;

Para cada departamento comprobamos que todos los empleados tienen un salario positivo. Si un solo empleado tiene salary <= 0, la agregacion devuelve false.

EVERY se comporta como un Y logico sobre las filas:

  • todas true -> true
  • al menos una false -> false
  • ningun valor conocido true/false que contar -> NULL

Esa ultima linea importa: un agregado SQL no devuelve true para un grupo vacio. PostgreSQL devuelve NULL (desconocido) cuando no hay nada que plegar, asi que debes tratar ese caso de forma explicita en lugar de suponer que es "verdadero por vacuidad".

Roll-ups de validacion

El uso mas habitual es reducir muchas filas de detalle a un unico indicador de estado. El caso clasico: "se han enviado todas las lineas del pedido?".

SELECT user_id,
       EVERY(status = 'shipped') AS fully_shipped,
       COUNT(*)                  AS line_items
FROM orders
GROUP BY user_id;

Una sola fila con status <> 'shipped' pone fully_shipped en false. Es ideal para cuadros de mando e informes: una fila por usuario en lugar de recalcular la condicion en el codigo de la aplicacion.

EVERY encaja de forma natural con HAVING cuando solo quieres grupos "limpios":

SELECT u.country, EVERY(o.amount > 0) AS all_positive
FROM users u
JOIN orders o ON o.user_id = u.id
GROUP BY u.country
HAVING EVERY(o.amount > 0);

EVERY frente a BOOL_AND

Funcionalmente EVERY(x) y BOOL_AND(x) son identicos en PostgreSQL; son sinonimos. La diferencia es pura legibilidad:

  • EVERY esta en el estandar SQL y se lee como una frase normal: "every order is shipped".
  • BOOL_AND deja explicita la naturaleza booleana para quien piensa en banderas.
-- mismo resultado
SELECT EVERY(amount > 0)    FROM orders;
SELECT BOOL_AND(amount > 0) FROM orders;

Consejo: usa EVERY en informes y vistas que leen los analistas, y BOOL_AND (junto con su pareja BOOL_OR) en codigo interno, para que la intencion "todas / al menos una" se vea de un vistazo.

Tratamiento de NULL

Esta es la trampa principal. EVERY ignora las filas donde el argumento es NULL, igual que el resto de agregados.

SELECT EVERY(status = 'shipped') AS result
FROM orders
WHERE id IN (1, 2);  -- supongamos que la fila 2 tiene status IS NULL
  • Si una fila tiene status IS NULL, entonces status = 'shipped' evalua a NULL y esa fila no se cuenta.
  • Si, tras descartar las filas NULL, no queda ninguna fila en el grupo, EVERY devuelve NULL, no true.

Gotcha: podrias suponer que un estado NULL "suspende" la comprobacion, pero se ignora en silencio. Si NULL debe contar como violacion, normaliza la expresion de forma explicita:

SELECT EVERY(COALESCE(status, 'pending') = 'shipped') AS strict
FROM orders
GROUP BY user_id;

Envuelve el propio agregado en COALESCE si prefieres que un grupo totalmente vacio se lea como un fallo en lugar de NULL.

MySQL y ClickHouse

El EVERY estandar no esta disponible en todas partes:

  • PostgreSQL — soporte completo de EVERY y BOOL_AND.
  • MySQL — no tiene ni EVERY ni BOOL_AND. Emulalo con MIN: MIN(condition) vale 1 solo cuando la condicion es cierta en todas partes.
-- MySQL: equivalente de EVERY(amount > 0)
SELECT user_id, MIN(amount > 0) = 1 AS all_positive
FROM orders
GROUP BY user_id;
  • ClickHouse — ofrece min y varios combinadores comodos; el camino idiomatico es el mismo truco con min(cond) o el agregado minIf.

Recuerda lo esencial: EVERY significa "todas las filas contadas pasaron la comprobacion", ignora NULL y devuelve NULL (no true) en un grupo vacio. Para una validacion estricta, decide el destino de NULL de forma explicita con COALESCE dentro del argumento o alrededor del resultado.

Practica con ejercicios reales

Resuelve ejercicios en el entrenador de SQL con corrección instantánea y pistas.

Abrir el entrenador