ALL Operator in PostgreSQL

Learn how to use the PostgreSQL ALL operator to compare a value against every value in a subquery result, returning true only when the comparison holds for all values in the set.

5 min read · Back to overview

Quick Answer

The PostgreSQL ALL operator compares a value to every value returned by a subquery. It returns true only if the comparison is true for every single value in the set. If the subquery returns no rows, ALL returns true.

Spin up a Postgres database in 20 seconds with Vela.

Try Vela Sandbox

The PostgreSQL ALL operator compares a value to every value in a set returned by a subquery. It returns true only when the comparison is true for every element in the set. If the subquery returns zero rows, ALL always returns true — because there are no counterexamples. This makes ALL the strict counterpart to ANY.

Syntax

expression operator ALL (subquery)
  • operator must be a comparison operator: =, <>, >, >=, <, <=.
  • The subquery must return exactly one column.
  • If the subquery returns zero rows, ALL evaluates to true for any operator.

Key semantics by operator:

ExpressionMeaning
value > ALL(subquery)value is greater than the maximum of the set
value < ALL(subquery)value is less than the minimum of the set
value = ALL(subquery)value equals every element (all elements identical)
value <> ALL(subquery)value does not match any element (equivalent to NOT IN)

Practical Example

Create a products table and a premium_tier table that defines the price range of premium products:

CREATE TABLE products (
  product_id   SERIAL PRIMARY KEY,
  name         VARCHAR(100) NOT NULL,
  category     VARCHAR(50),
  unit_price   NUMERIC(10, 2) NOT NULL
);

CREATE TABLE premium_tier (
  tier_id      SERIAL PRIMARY KEY,
  product_id   INT REFERENCES products (product_id),
  tier_price   NUMERIC(10, 2) NOT NULL
);

INSERT INTO products (name, category, unit_price) VALUES
  ('Budget Case',    'Accessories',  8.99),
  ('Standard Case',  'Accessories', 19.99),
  ('Pro Case',       'Accessories', 34.99),
  ('Elite Case',     'Accessories', 75.00),
  ('Budget Stand',   'Accessories',  5.50),
  ('Pro Stand',      'Accessories', 28.00);

INSERT INTO premium_tier (product_id, tier_price) VALUES
  (3, 34.99),
  (4, 75.00),
  (6, 28.00);

Products priced higher than all premium tier prices

Find products whose unit price exceeds every premium tier price — meaning they cost more than the most expensive premium product:

SELECT product_id, name, unit_price
FROM products
WHERE unit_price > ALL (
  SELECT tier_price
  FROM premium_tier
)
ORDER BY unit_price;

The highest premium tier price is 75.00. No product in this dataset exceeds that, so the query returns zero rows. If Elite Case were priced at 100.00, it would be the sole result.

Products priced lower than all premium tier prices

Find products cheaper than every premium tier price — meaning they cost less than the least expensive premium product (28.00):

SELECT product_id, name, unit_price
FROM products
WHERE unit_price < ALL (
  SELECT tier_price
  FROM premium_tier
)
ORDER BY unit_price;
 product_id |     name      | unit_price
------------+---------------+------------
          5 | Budget Stand  |       5.50
          1 | Budget Case   |       8.99
          2 | Standard Case |      19.99
(3 rows)

All three products cost less than 28.00 (the minimum premium tier price), so they satisfy < ALL.

Using <> ALL to exclude specific values

Find all products whose price does not match any premium tier price (equivalent to NOT IN):

SELECT product_id, name, unit_price
FROM products
WHERE unit_price <> ALL (
  SELECT tier_price
  FROM premium_tier
)
ORDER BY unit_price;
 product_id |     name      | unit_price
------------+---------------+------------
          5 | Budget Stand  |       5.50
          1 | Budget Case   |       8.99
          2 | Standard Case |      19.99
(3 rows)

ALL vs. ANY vs. NOT IN

PatternReturns true whenEmpty set result
> ALL(subquery)value > max of settrue (vacuous)
< ALL(subquery)value < min of settrue (vacuous)
<> ALL(subquery)value matches no elementtrue (vacuous)
= ANY(subquery) / INvalue matches at least onefalse
NOT IN(subquery)value matches no elementtrue

NULL caveat: <> ALL and NOT IN both behave identically when a NULL appears in the subquery result — the comparison evaluates to NULL (unknown) rather than true, silently excluding all rows. Use NOT EXISTS when the subquery column is nullable.

Testing with Vela

ALL with an empty subquery silently passes every row, which can lead to unintended full-table access in production if the lookup table is empty. Vela’s database branching lets you clone your production database, introduce edge cases (like an empty premium tier), and verify query behavior before deploying to production.

Production Tips

  • Index the column used in the ALL subquery (e.g., tier_price) to avoid sequential scans inside the subquery.
  • Use EXPLAIN ANALYZE to verify the inner scan is efficient — the planner sometimes rewrites > ALL as > (SELECT MAX(...)).
  • > ALL(subquery) is semantically equivalent to > (SELECT MAX(col) FROM ...). For readability, the MAX form can be clearer in code reviews.
  • <> ALL and NOT IN are equivalent in behavior but both fail silently when the subquery contains NULLs. Prefer NOT EXISTS for nullable columns.
  • When the subquery might legitimately return zero rows and vacuous truth is not the desired behavior, add a guard: WHERE EXISTS (SELECT 1 FROM premium_tier) AND unit_price > ALL (SELECT tier_price FROM premium_tier).

Continue in Subquery: EXISTS Operator.

Related in this section: Subquery · Correlated Subquery · ANY Operator

Frequently Asked Questions

What does the ALL operator do in PostgreSQL?
ALL compares a value against every value in the set returned by a subquery. The result is true only when the comparison holds for every single element. For example, value > ALL(subquery) returns true only if value is greater than the largest value in the set.
Does ALL lock the table it queries?
The subquery inside ALL behaves like a regular SELECT and acquires only a ROW SHARE lock under normal read-committed isolation. The ALL operator does not impose any additional locking beyond what the outer statement holds on its own tables.
What happens when the ALL subquery returns no rows?
When the subquery returns an empty set, ALL evaluates to true for any comparison. The logic is vacuous truth: with no elements to check, no counterexample can exist. This is the opposite of ANY, which returns false for an empty set. Always consider whether an empty subquery result is valid in your use case.
Can I use IF EXISTS with ALL?
There is no IF EXISTS guard for ALL. If you need to handle an empty subquery differently, check for rows first with EXISTS, or use a CASE expression to short-circuit when the subquery is empty.
What is the safest way to use ALL in production?
Index the column in the subquery (e.g., the salary or price column) to avoid sequential scans. Use EXPLAIN ANALYZE to verify the plan. Be aware that <> ALL is equivalent to NOT IN — and like NOT IN, it returns NULL (not false) for every row if any element in the subquery is NULL. Prefer NOT EXISTS when NULLs are possible.