PostgreSQLWHERE Clause

WHERE Clause

WHERE filters rows: given a candidate row, its condition evaluates to true, false, or unknown (when NULL is involved), and only rows where it evaluates to true are kept. It is the single most commonly used clause after SELECT itself, and it works the same way across SELECT, UPDATE, and DELETE.

Basic filtering

Rows matching a single condition

SQL
SELECT sku, name, stock_qty
FROM products
WHERE stock_qty < 20;
 sku      | name          | stock_qty
----------+---------------+-----------
 SKU-1004 | Laptop Stand  |         8
Combining conditions

More than one condition can be combined with AND, OR, and NOT to express more specific filters. The full set of comparison, logical, and pattern-matching operators available inside a WHERE clause is large enough to deserve its own page — see the Operators page for the complete map.

Combining conditions with AND / OR

SQL
SELECT sku, name, unit_price, stock_qty
FROM products
WHERE stock_qty < 20
  AND (unit_price > 50 OR name ILIKE '%stand%');
WHERE and the logical execution order

WHERE runs early in a query's conceptual execution — right after the source rows are identified in FROM, and before any grouping happens. That ordering has a direct consequence: WHERE can only see and filter individual rows, never the results of an aggregate like COUNT(*) or SUM(...), because those aggregates have not been computed yet at the point WHERE runs.

This does NOT work — aggregates are not available yet in WHERE

SQL
SELECT customer_id, COUNT(*) AS order_count
FROM orders
WHERE COUNT(*) > 5   -- invalid: WHERE runs before GROUP BY / aggregation
GROUP BY customer_id;
ERROR: aggregate functions are not allowed in WHERE
Filter groups with HAVING, not WHERE
Filtering on the result of an aggregate — "customers with more than 5 orders," "products where total revenue exceeds $10,000" — is what HAVING is for, since HAVING runs after GROUP BY has produced its groups. WHERE filters rows before grouping; HAVING filters groups after grouping. The HAVING page covers this distinction with worked examples.
Filter as early as possible
Because WHERE runs before grouping and before the final column list is computed, putting as much filtering as possible into WHERE (rather than filtering later, or in application code after the fact) lets PostgreSQL discard non-matching rows early — often letting it use an index to avoid scanning the whole table at all.
  • WHERE filters individual rows based on a boolean condition.

  • Multiple conditions combine with AND, OR, and NOT.

  • WHERE runs before GROUP BY, so it cannot reference aggregate functions.

  • HAVING is the equivalent tool for filtering after grouping, covered on its own page.