Learn how to use the PostgreSQL WHERE clause in SELECT statements to filter records with comparison operators, logical conditions, and practical SQL examples.
The WHERE clause is used to filter records from a table. It returns only the rows that satisfy the specified condition.
We will use the PostgreSQL DVD Rental (dvdrental) database examples.
SELECT column1, column2, ...
FROM table_name
WHERE condition;
SELECT first_name, last_name
FROM customer
WHERE first_name = 'Mary';
This returns customers whose first name is Mary.
PostgreSQL supports the following common comparison operators:
| Operator | Meaning |
|---|---|
= |
Equal to |
<> |
Not equal to |
!= |
Not equal to |
> |
Greater than |
< |
Less than |
>= |
Greater than or equal to |
<= |
Less than or equal to |
= Equal ToSELECT *
FROM customer
WHERE store_id = 1;
Returns customers belonging to store 1.
<> Not Equal ToSELECT *
FROM customer
WHERE store_id <> 1;
!= Not Equal ToSELECT *
FROM customer
WHERE store_id != 1;
<> and != both mean not equal in PostgreSQL.
> Greater ThanSELECT title, rental_rate
FROM film
WHERE rental_rate > 3;
< Less ThanSELECT title, rental_rate
FROM film
WHERE rental_rate < 2;
>= Greater Than or Equal ToSELECT title, length
FROM film
WHERE length >= 130;
<= Less Than or Equal ToSELECT payment_id, customer_id, amount
FROM payment
WHERE amount <= 4.99;
Logical operators allow us to combine multiple conditions.
| Operator | Purpose |
|---|---|
AND |
All conditions must be true |
OR |
At least one condition must be true |
NOT |
Reverses a condition |
ANDBoth conditions must be true.
SELECT title, rental_rate, length
FROM film
WHERE rental_rate > 2
AND length > 120;
Meaning: Find films with a rental rate greater than 2 and length greater than 120 minutes.
ORAt least one condition must be true.
SELECT title, length
FROM film
WHERE length < 60
OR length > 120;
Meaning: Display films that are less than 60 minutes OR greater than 120 minutes.
NOTReverses the condition.
SELECT title, rental_rate
FROM film
WHERE NOT rental_rate = 2.99;
This returns films whose rental rate is not 2.99.
BETWEEN OperatorBETWEEN checks whether a value falls within a range.
SELECT title, length
FROM film
WHERE length BETWEEN 90 AND 120;
BETWEEN is inclusive, so values 90 and 120 are included.
It is equivalent to:
WHERE length >= 90
AND length <= 120;
NOT BETWEENSELECT title, length
FROM film
WHERE length NOT BETWEEN 90 AND 120;
IN OperatorIN checks whether a value matches any value in a list.
SELECT first_name, last_name, store_id
FROM customer
WHERE store_id IN (1, 2);
This is easier than writing:
WHERE store_id = 1
OR store_id = 2;
NOT INSELECT first_name, last_name, store_id
FROM customer
WHERE store_id NOT IN (1, 2);
LIKE OperatorLIKE is used for pattern matching.
% Wildcard% represents zero or more characters.
SELECT first_name, last_name
FROM customer
WHERE first_name LIKE 'A%';
Finds names beginning with A.
Examples:
Adam
Alice
Andrew
Amanda
SELECT first_name, last_name
FROM customer
WHERE first_name LIKE '%a';
Finds names ending with a.
SELECT first_name, last_name
FROM customer
WHERE first_name LIKE '%an%';
Finds names containing an.
_ WildcardThe underscore _ represents exactly one character.
SELECT first_name,last_name,email
FROM customer
WHERE first_name LIKE 'A____';
This searches for names beginning with A followed by exactly four characters.
For example:
Alice
Aaron
ILIKE OperatorPostgreSQL provides ILIKE for case-insensitive pattern matching.
SELECT first_name, last_name
FROM customer
WHERE first_name ILIKE 'a%';
It can match:
Adam
alice
AMANDA
Andrew
Compare:
LIKE
with:
ILIKE
ILIKE ignores differences between uppercase and lowercase letters.
NOT LIKESELECT first_name, last_name
FROM customer
WHERE first_name NOT LIKE 'A%';
Returns customers whose first name does not start with A.
IS NULLNULL means that a value is missing or unknown.
We cannot use:
WHERE column = NULL
Instead, use:
IS NULL
Example:
SELECT *
FROM address
WHERE address2 IS NULL;
IS NOT NULLSELECT rental_id, rental_date, return_date
FROM rental
WHERE return_date IS NOT NULL;
Meaning: Display rentals where the movie has been returned.
ANYANY compares a value with values returned by an array or subquery.
Example:
SELECT title, rental_rate
FROM film
WHERE rental_rate = ANY (ARRAY[0.99, 2.99, 4.99]);
This means the rental rate matches any value in the array. ANY works with an array or subquery and can be combined with comparison operators such as >, <, >=, etc.
ALLALL requires the comparison to be true for every value returned by the expression.
Example:
SELECT title, rental_rate
FROM film
WHERE rental_rate > ALL (ARRAY[0.99, 1.99]);
The rental rate must be greater than both 0.99 and 1.99.
PostgreSQL also supports regular-expression matching.
~Case-sensitive regular expression matching.
SELECT first_name
FROM customer
WHERE first_name ~ '^A';
Names beginning with A.
~*Case-insensitive regular expression matching.
SELECT first_name
FROM customer
WHERE first_name ~* '^a';
!~Does not match a regular expression.
SELECT first_name
FROM customer
WHERE first_name !~ '^A';
!~*Case-insensitive negative regular expression matching.
SELECT first_name
FROM customer
WHERE first_name !~* '^a';
You can combine several operators in one WHERE clause.
SELECT title, rental_rate, length
FROM film
WHERE rental_rate >= 2
AND rental_rate <= 4
AND length > 100;
Another example:
SELECT first_name, last_name, store_id
FROM customer
WHERE store_id IN (1, 2)
AND first_name ILIKE 'a%';
Parentheses are important when using AND and OR.
SELECT title, rental_rate
FROM film
WHERE (rental_rate = 2.99 OR rental_rate = 4.99)
AND length > 100;
Without parentheses, the result may not be what you expect because PostgreSQL evaluates AND before OR.
WHERE with DatesThe DVD Rental database contains date/time columns.
Example:
SELECT payment_id, customer_id, amount, payment_date
FROM payment
WHERE payment_date >= '2007-02-15';
SELECT payment_id, customer_id, amount, payment_date
FROM payment
WHERE payment_date BETWEEN '2007-02-15' AND '2007-02-20';
WHERE with Numeric ValuesSELECT payment_id, customer_id, amount
FROM payment
WHERE amount > 5;
Multiple conditions:
SELECT payment_id, customer_id, amount
FROM payment
WHERE amount >= 5
AND amount <= 10;
Or:
SELECT payment_id, customer_id, amount
FROM payment
WHERE amount BETWEEN 5 AND 10;
WHERE with TextSELECT first_name, last_name
FROM customer
WHERE last_name = 'Smith';
Case-insensitive search:
SELECT first_name, last_name
FROM customer
WHERE last_name ILIKE 'smith';
Partial search:
SELECT first_name, last_name
FROM customer
WHERE last_name ILIKE '%son%';
WHERE vs HAVINGWHEREFilters individual rows before grouping.
SELECT *
FROM payment
WHERE amount > 5;
HAVINGFilters groups after GROUP BY.
SELECT customer_id, COUNT(*)
FROM payment
GROUP BY customer_id
HAVING COUNT(*) > 10;
A simple rule for students:
WHERE → filter rows HAVING → filter groups
Suppose we want to find customers:
ASELECT customer_id, first_name, last_name, store_id
FROM customer
WHERE store_id IN (1, 2)
AND first_name ILIKE 'A%'
AND customer_id > 10;
This demonstrates:
INILIKE>AND| Category | Operators |
|---|---|
| Equality | = |
| Not equal | <>, != |
| Comparison | >, <, >=, <= |
| Logical | AND, OR, NOT |
| Range | BETWEEN, NOT BETWEEN |
| List | IN, NOT IN |
| Pattern | LIKE, NOT LIKE |
| Case-insensitive pattern | ILIKE |
| NULL | IS NULL, IS NOT NULL |
| Array/Subquery comparison | ANY, ALL |
| Regular expression | ~, ~*, !~, !~* |
Using the DVD Rental database, write SQL queries to:
store_id = 1.3.2 and 4.M.son.IN.5.2 and 6.address2 is NULL.address2 is not NULL.love, ignoring case.A.customer_id > 100 and store_id = 1.A or B.EXISTS.SELECT columns
FROM table
WHERE condition;
Think of WHERE as a filter:
Table → WHERE condition → Only matching rows → SELECT output.