EVERY is an aggregate that collapses a group of boolean values into one: it returns true only when the condition holds for every counted row in the group. It is the SQL-standard synonym for BOOL_AND, and it is exactly what you reach for when the question is "do all rows satisfy this rule?"
Basic syntax
EVERY takes a boolean expression evaluated per row. The result is true if every counted row yielded true, and false if at least one yielded false.
SELECT dept, EVERY(salary > 0) AS all_paid
FROM employees
GROUP BY dept;
For each department we assert that every employee has a positive salary. If a single employee has salary <= 0, the aggregate returns false.
EVERY behaves like a logical AND across rows:
- all
true -> true
- at least one
false -> false
- no known
true/false value to count -> NULL
That last line matters: a SQL aggregate does not return true for an empty group. PostgreSQL returns NULL (unknown) when there is nothing to fold, so you must handle that case explicitly rather than assume "vacuously true".
Validation rollups
The most common use is collapsing many detail rows into a single status flag. The classic case: "are all line items shipped?"
SELECT user_id,
EVERY(status = 'shipped') AS fully_shipped,
COUNT(*) AS line_items
FROM orders
GROUP BY user_id;
A single row with status <> 'shipped' flips fully_shipped to false. This is ideal for dashboards and reports: one row per user instead of recomputing the condition in application code.
EVERY pairs naturally with HAVING when you only want "clean" groups:
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 vs BOOL_AND
Functionally EVERY(x) and BOOL_AND(x) are identical in PostgreSQL; they are synonyms. The difference is pure readability:
EVERY is in the SQL standard and reads like plain English: "every order is shipped".
BOOL_AND makes the boolean nature explicit for readers who think in flags.
SELECT EVERY(amount > 0) FROM orders;
SELECT BOOL_AND(amount > 0) FROM orders;
Tip: use EVERY in reports and views read by analysts, and BOOL_AND (with its partner BOOL_OR) in plumbing code, so the "all / at least one" intent is obvious at a glance.
NULL handling
This is the main trap. EVERY skips rows where the argument is NULL, just like every other aggregate.
SELECT EVERY(status = 'shipped') AS result
FROM orders
WHERE id IN (1, 2);
- If a row has
status IS NULL, then status = 'shipped' evaluates to NULL, and that row is not counted.
- If, after dropping
NULL rows, no row remains in the group, EVERY returns NULL, not true.
Gotcha: you might assume a NULL status would "fail" the check, but it is silently ignored. If NULL should count as a violation, normalize the expression explicitly:
SELECT EVERY(COALESCE(status, 'pending') = 'shipped') AS strict
FROM orders
GROUP BY user_id;
Wrap the aggregate itself in COALESCE instead if you want a fully empty group to read as a failure rather than NULL.
MySQL and ClickHouse
The standard EVERY is not available everywhere:
- PostgreSQL — full support for both
EVERY and BOOL_AND.
- MySQL — has neither
EVERY nor BOOL_AND. Emulate with MIN: MIN(condition) equals 1 only when the condition is true everywhere.
SELECT user_id, MIN(amount > 0) = 1 AS all_positive
FROM orders
GROUP BY user_id;
- ClickHouse — offers
min plus handy combinators; the idiomatic path is the same min(cond) trick or the minIf aggregate.
Remember the essentials: EVERY means "all counted rows passed the check", it ignores NULL, and it returns NULL (not true) on an empty group. For strict validation, decide the fate of NULL explicitly with COALESCE inside the argument or around the result.
EVERYis an aggregate that collapses a group of boolean values into one: it returnstrueonly when the condition holds for every counted row in the group. It is the SQL-standard synonym forBOOL_AND, and it is exactly what you reach for when the question is "do all rows satisfy this rule?"Basic syntax
EVERYtakes a boolean expression evaluated per row. The result istrueif every counted row yieldedtrue, andfalseif at least one yieldedfalse.SELECT dept, EVERY(salary > 0) AS all_paid FROM employees GROUP BY dept;For each department we assert that every employee has a positive salary. If a single employee has
salary <= 0, the aggregate returnsfalse.EVERYbehaves like a logical AND across rows:true->truefalse->falsetrue/falsevalue to count ->NULLThat last line matters: a SQL aggregate does not return
truefor an empty group. PostgreSQL returnsNULL(unknown) when there is nothing to fold, so you must handle that case explicitly rather than assume "vacuously true".Validation rollups
The most common use is collapsing many detail rows into a single status flag. The classic case: "are all line items shipped?"
SELECT user_id, EVERY(status = 'shipped') AS fully_shipped, COUNT(*) AS line_items FROM orders GROUP BY user_id;A single row with
status <> 'shipped'flipsfully_shippedtofalse. This is ideal for dashboards and reports: one row per user instead of recomputing the condition in application code.EVERYpairs naturally withHAVINGwhen you only want "clean" groups: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 vs BOOL_AND
Functionally
EVERY(x)andBOOL_AND(x)are identical in PostgreSQL; they are synonyms. The difference is pure readability:EVERYis in the SQL standard and reads like plain English: "every order is shipped".BOOL_ANDmakes the boolean nature explicit for readers who think in flags.-- identical results SELECT EVERY(amount > 0) FROM orders; SELECT BOOL_AND(amount > 0) FROM orders;Tip: use
EVERYin reports and views read by analysts, andBOOL_AND(with its partnerBOOL_OR) in plumbing code, so the "all / at least one" intent is obvious at a glance.NULL handling
This is the main trap.
EVERYskips rows where the argument isNULL, just like every other aggregate.SELECT EVERY(status = 'shipped') AS result FROM orders WHERE id IN (1, 2); -- suppose row 2 has status IS NULLstatus IS NULL, thenstatus = 'shipped'evaluates toNULL, and that row is not counted.NULLrows, no row remains in the group,EVERYreturnsNULL, nottrue.Gotcha: you might assume a
NULLstatus would "fail" the check, but it is silently ignored. IfNULLshould count as a violation, normalize the expression explicitly:SELECT EVERY(COALESCE(status, 'pending') = 'shipped') AS strict FROM orders GROUP BY user_id;Wrap the aggregate itself in
COALESCEinstead if you want a fully empty group to read as a failure rather thanNULL.MySQL and ClickHouse
The standard
EVERYis not available everywhere:EVERYandBOOL_AND.EVERYnorBOOL_AND. Emulate withMIN:MIN(condition)equals1only when the condition is true everywhere.-- MySQL: equivalent of EVERY(amount > 0) SELECT user_id, MIN(amount > 0) = 1 AS all_positive FROM orders GROUP BY user_id;minplus handy combinators; the idiomatic path is the samemin(cond)trick or theminIfaggregate.Remember the essentials:
EVERYmeans "all counted rows passed the check", it ignoresNULL, and it returnsNULL(nottrue) on an empty group. For strict validation, decide the fate ofNULLexplicitly withCOALESCEinside the argument or around the result.