sqlpostgresqlaggregateboolean

EVERY no SQL: validar uma condicao para todo o grupo

EVERY e o sinonimo padrao de BOOL_AND: true quando a condicao vale para cada linha contada, NULL sobre um grupo vazio.

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

EVERY e uma funcao de agregacao que reduz um grupo de valores booleanos a um so: ela retorna true apenas quando a condicao vale para todas as linhas contadas do grupo. E o sinonimo padrao de BOOL_AND e e exatamente o que voce usa quando a pergunta e "todas as linhas satisfazem esta regra?".

Sintaxe basica

EVERY recebe uma expressao booleana avaliada por linha. O resultado e true se todas as linhas contadas deram true, e false se ao menos uma deu false.

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

Para cada departamento verificamos que todo funcionario tem salario positivo. Se um unico funcionario tiver salary <= 0, a agregacao retorna false.

EVERY se comporta como um E logico sobre as linhas:

  • todas true -> true
  • ao menos uma false -> false
  • nenhum valor conhecido true/false para contar -> NULL

Essa ultima linha importa: um agregado SQL nao retorna true para um grupo vazio. O PostgreSQL retorna NULL (desconhecido) quando nao ha nada a reduzir, entao voce precisa tratar esse caso de forma explicita em vez de supor que seja "verdadeiro por vacuidade".

Roll-ups de validacao

O uso mais comum e reduzir varias linhas de detalhe a um unico indicador de estado. O caso classico: "todos os itens do pedido foram enviados?".

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

Uma unica linha com status <> 'shipped' muda fully_shipped para false. E ideal para dashboards e relatorios: uma linha por usuario em vez de recalcular a condicao no codigo da aplicacao.

EVERY combina naturalmente com HAVING quando voce quer apenas grupos "limpos":

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 versus BOOL_AND

Funcionalmente EVERY(x) e BOOL_AND(x) sao identicos no PostgreSQL; sao sinonimos. A diferenca e pura legibilidade:

  • EVERY esta no padrao SQL e se le como uma frase comum: "every order is shipped".
  • BOOL_AND deixa explicita a natureza booleana para quem pensa em flags.
-- mesmo resultado
SELECT EVERY(amount > 0)    FROM orders;
SELECT BOOL_AND(amount > 0) FROM orders;

Dica: use EVERY em relatorios e views lidas por analistas, e BOOL_AND (com sua dupla BOOL_OR) em codigo de infraestrutura, para que a intencao "todas / ao menos uma" fique obvia num relance.

Tratamento de NULL

Esta e a principal armadilha. EVERY ignora as linhas em que o argumento e NULL, assim como os demais agregados.

SELECT EVERY(status = 'shipped') AS result
FROM orders
WHERE id IN (1, 2);  -- suponha que a linha 2 tem status IS NULL
  • Se uma linha tem status IS NULL, entao status = 'shipped' resulta em NULL, e essa linha nao e contada.
  • Se, apos descartar as linhas NULL, nenhuma linha sobrar no grupo, EVERY retorna NULL, e nao true.

Gotcha: voce pode supor que um status NULL "reprova" a verificacao, mas ele e ignorado em silencio. Se NULL deve contar como violacao, normalize a expressao de forma explicita:

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

Envolva o proprio agregado em COALESCE se preferir que um grupo totalmente vazio seja lido como falha em vez de NULL.

MySQL e ClickHouse

O EVERY padrao nao esta disponivel em todo lugar:

  • PostgreSQL — suporte completo a EVERY e BOOL_AND.
  • MySQL — nao tem nem EVERY nem BOOL_AND. Emule com MIN: MIN(condition) vale 1 somente quando a condicao e verdadeira em toda parte.
-- MySQL: equivalente de EVERY(amount > 0)
SELECT user_id, MIN(amount > 0) = 1 AS all_positive
FROM orders
GROUP BY user_id;
  • ClickHouse — oferece min e varios combinadores praticos; o caminho idiomatico e o mesmo truque com min(cond) ou o agregado minIf.

Lembre do essencial: EVERY significa "todas as linhas contadas passaram na verificacao", ignora NULL e retorna NULL (nao true) num grupo vazio. Para validacao estrita, decida o destino do NULL de forma explicita com COALESCE dentro do argumento ou ao redor do resultado.

Pratique com exercícios reais

Resolva exercícios no treinador de SQL com correção instantânea e dicas.

Abrir o treinador