PostgreSQL WHERE

How the PostgreSQL WHERE clause works: filtering rows with comparison operators, AND/OR/NOT, BETWEEN, IN, LIKE, IS NULL, and indexing for fast filtering.

10 min read · Last updated: March 2026 · Back to overview

Quick Answer

The WHERE clause filters rows returned by SELECT, UPDATE, or DELETE. It evaluates a Boolean condition for each row — only rows where the condition is TRUE are included in the result. WHERE is evaluated before SELECT, so column aliases are not available in WHERE.

Spin up a Postgres database in 20 seconds with Vela.

Try Vela Sandbox

Introduction to PostgreSQL WHERE

The WHERE clause filters rows in SELECT, UPDATE, and DELETE statements. Only rows where the condition evaluates to TRUE are included (or affected).

SELECT select_list
FROM table_name
WHERE condition;

Comparison operators

-- Equal to
SELECT * FROM customer WHERE last_name = 'Smith';

-- Not equal
SELECT * FROM product WHERE price != 0;

-- Greater than / less than
SELECT * FROM orders WHERE total_amount > 100;

-- Range
SELECT * FROM orders WHERE placed_at >= '2024-01-01' AND placed_at < '2025-01-01';

BETWEEN

BETWEEN x AND y is inclusive on both ends (equivalent to >= x AND <= y):

SELECT * FROM payment WHERE amount BETWEEN 1.00 AND 5.00;

IN: matching a list of values

SELECT * FROM customer WHERE country IN ('US', 'CA', 'GB');

-- Exclusion
SELECT * FROM product WHERE category_id NOT IN (5, 10, 15);

LIKE: pattern matching

-- Starts with 'Ann'
SELECT * FROM customer WHERE first_name LIKE 'Ann%';

-- Contains 'gmail' (case-insensitive with ILIKE)
SELECT * FROM customer WHERE email ILIKE '%gmail%';

% matches any sequence of characters; _ matches exactly one character.

IS NULL / IS NOT NULL

-- Customers with no phone number on file
SELECT * FROM customer WHERE phone IS NULL;

-- Orders with a tracking number
SELECT * FROM orders WHERE tracking_number IS NOT NULL;

Combining conditions

SELECT *
FROM orders
WHERE status = 'shipped'
  AND placed_at >= now() - interval '7 days'
  AND total_amount > 50
ORDER BY placed_at DESC;

Subqueries in WHERE

-- Customers who placed at least one order over $500
SELECT * FROM customer
WHERE customer_id IN (
  SELECT customer_id FROM orders WHERE total_amount > 500
);

Production tips

  • Index columns used in WHERE for equality and range queries. Unindexed filters on large tables cause full sequential scans.
  • Be wary of NOT IN with a subquery that might return NULL — if any value in the list is NULL, NOT IN returns no rows. Use NOT EXISTS instead for nullable subqueries.
  • Avoid wrapping indexed columns in functions (WHERE lower(email) = 'x' skips the index). Use a functional index or ILIKE instead.
  • Test filter selectivity with EXPLAIN ANALYZE — the planner uses table statistics to estimate row counts.

Reference: PostgreSQL documentation — SELECT / WHERE.

Continue in Filtering Data: AND Operator.

Related in this section: AND Operator · OR Operator · LIMIT

Frequently Asked Questions

What operators can I use in a PostgreSQL WHERE clause?

PostgreSQL WHERE supports: comparison operators (=, !=, <, >, <=, >=), range operators (BETWEEN x AND y), list membership (IN (val1, val2)), pattern matching (LIKE '%pattern%', ILIKE for case-insensitive), NULL checks (IS NULL, IS NOT NULL), logical operators (AND, OR, NOT), and subquery operators (EXISTS, ANY, ALL). You can combine multiple conditions with AND/OR and control precedence with parentheses.

Can I use a column alias in WHERE?

No. The WHERE clause is evaluated before SELECT, so column aliases defined in the SELECT list are not available in WHERE. Use the original expression instead. For example, if you define total_amount * 1.1 AS total_with_tax in SELECT, you must repeat the expression in WHERE, not use the alias. You can use aliases in ORDER BY and HAVING.

How does PostgreSQL handle NULL in WHERE conditions?

NULL represents an unknown value — any comparison with NULL (NULL = NULL, NULL > 5) evaluates to NULL (not TRUE or FALSE), so the row is excluded. To filter for NULL values, use IS NULL or IS NOT NULL — never use = NULL. In boolean logic, NULL OR TRUE evaluates to TRUE, but NULL AND TRUE evaluates to NULL.

How do I make WHERE clause filters faster in PostgreSQL?

Create indexes on columns used frequently in WHERE conditions. B-tree indexes (the default) support =, <, >, BETWEEN, and IN. For LIKE patterns, a B-tree index only helps if the pattern starts with a literal ('abc%') — use pg_trgm extension and GIN index for contains-style search ('%abc%'). Use EXPLAIN ANALYZE to verify that your index is being used and not bypassed by a sequential scan.