Module 9 already established that only PostgreSQL has a genuinely native, enforced BOOLEAN type, everyone else fakes it with an integer, a bit, or a constrained character column. That same split carries straight into aggregation: only PostgreSQL has real boolean aggregate functions.
Learning Objectives
- Use PostgreSQL's bool_and(), bool_or(), and every(), the one database here with native boolean aggregates.
- Explain why every() and bool_and() are the exact same function under two different names.
- Build the honest MIN/MAX-over-0-and-1 equivalent for the five databases with no native boolean type to aggregate.
Group of True/False Values
e.g. did every project ship on time?
bool_and() / bool_or()
PostgreSQL's native boolean aggregates
MIN/MAX over 0 and 1
The honest workaround everywhere else
PostgreSQL's Native Boolean Aggregates
bool_and() returns true only if every value in the group is true, bool_or() returns true if at least one value in the group is true. every() is the exact SQL-standard name for the same function as bool_and(), both exist on PostgreSQL and behave identically, a naming choice, not two different functions.
SELECT project_id,
BOOL_AND(completed_on_time) AS every_task_on_time,
BOOL_OR(completed_on_time) AS at_least_one_task_on_time
FROM project_tasks
GROUP BY project_id;Everyone Else: MIN/MAX Over 0 and 1
With a flag stored as 0/1 (or a faked boolean type that's really one underneath), MIN() across the group is 0 unless every row is 1, exactly BOOL_AND's logic, and MAX() is 1 if any row is 1, exactly BOOL_OR's logic. The same arithmetic truth table, expressed through plain numeric aggregates instead of a dedicated boolean one.
SELECT project_id,
MIN(completed_on_time) AS every_task_on_time,
MAX(completed_on_time) AS at_least_one_task_on_time
FROM project_tasks
GROUP BY project_id;Try It Yourself
Find whether every task in project id 4 finished on time, on MySQL, using the MIN/MAX pattern.
SELECT MIN(completed_on_time) AS every_task_on_time FROM project_tasks WHERE project_id = 4;
Frequently Asked Questions
Why are bool_and() and every() the same function on PostgreSQL?
bool_and() is PostgreSQL's own original name, every() is the exact name the SQL standard specifies for the identical logic. PostgreSQL implements both, pointing at the same underlying aggregate, so either name can be used interchangeably there.
Does the MIN/MAX workaround handle NULL the same way bool_and/bool_or does?
Both skip NULL values the same way every other aggregate in this course does, a group that's entirely NULL returns NULL either way. The equivalence holds as long as the flag column is genuinely only ever 0, 1, or NULL, never anything else.
Common Beginner Mistakes
Expecting BOOL_AND or BOOL_OR to exist on MySQL, SQL Server, or Oracle
They don't, none of the three has a real boolean aggregate function, MIN()/MAX() over the 0/1-valued column is the honest, correct equivalent there, not a differently-named built-in waiting to be found.
Using SUM() instead of MIN()/MAX() to check "did everything happen"
SUM() answers a different question entirely, how many rows were true, not whether all of them were, or at least one was. MIN() (all true) and MAX() (at least one true) are the ones that actually match bool_and's and bool_or's logic.
Best Practices
- On PostgreSQL, use bool_and()/bool_or() directly on a real BOOLEAN column rather than faking it with 0/1 the way the other five databases have to.
- Everywhere else, be explicit that MIN()/MAX() is standing in for a boolean aggregate, a comment or a clearly-named column alias keeps the intent obvious to a future reader.
- Confirm the flag column genuinely only ever holds 0, 1, or NULL before relying on the MIN/MAX equivalence, any other value breaks the logic.
Interview Questions
How would you check whether every row in a group satisfies a boolean condition, on a database with no BOOL_AND function?
Express the condition as a 0/1-valued expression (a CASE WHEN, or a column that's already stored that way) and take MIN() across the group, it's 1 (true) only if every row was 1, exactly BOOL_AND's logic, implemented with a plain numeric aggregate instead of a dedicated boolean one.
Why does only PostgreSQL have real boolean aggregate functions among these six databases?
PostgreSQL is the only one with a genuinely native, enforced BOOLEAN type in the first place, as Module 9 covered, every other database fakes booleans with an integer, a bit, or a constrained character column. A dedicated boolean aggregate needs a real boolean type to operate on, which only PostgreSQL actually has.
Summary
bool_and(), bool_or(), and the standard-named every() are PostgreSQL's native boolean aggregates, possible because PostgreSQL alone has a real, enforced BOOLEAN type. Every other database here fakes the identical logic with MIN() (all true) and MAX() (at least one true) over a 0/1-valued column.
What's Next?
APPROX_COUNT_DISTINCT, a fast, statistically approximate alternative to COUNT(DISTINCT ...) on a genuinely huge table, with real, specific version floors on the two databases that actually have it.
Ready to Practice SQL?
Write and run real SQL queries online, right in your browser, no install or signup required. Pick a playground based on which database you want to practice on.
Both open a third-party SQL playground in a new tab. External site terms and privacy policy apply.
Or try 50 SQL practice questions →