DevLearningTools

LEARN · SQL

SQL Boolean Aggregates (BOOL_AND / BOOL_OR / EVERY)

Aggregate a group of true/false values directly, PostgreSQL's native bool_and, bool_or, and every, the one database here with a real enforced BOOLEAN type to aggregate. Every other database fakes it with MIN/MAX over 0 and 1.

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.

PostgreSQL
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.

MySQL / MariaDB / SQL Server / Oracle / SQLite
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.

Answer
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.

SQLite / PostgreSQL

Fast, no server, no ads.

Open DB Fiddle ↗

MySQL / SQL Server

Switch databases with one dropdown.

Open SQL Fiddle ↗

Both open a third-party SQL playground in a new tab. External site terms and privacy policy apply.

Or try 50 SQL practice questions →