SQL WHERE: filter rows
A table often holds thousands of rows, when you only want a few of them: the customers of one city, the products under a given price, the cancelled orders… That is exactly what the WHERE clause does: it only keeps the rows that meet a condition.
Syntax
SELECT columns
FROM table
WHERE condition;How it works
For each row of the table, SQL evaluates the WHERE condition. If it is true, the row is kept; otherwise, it is discarded.
Comparison operators
| Operator | Meaning | Example |
|---|---|---|
= | equal to | ville = 'Lyon' |
<> or != | not equal to | statut <> 'annulée' |
<, > | strictly less / greater than | prix < 20 |
<=, >= | less / greater than or equal to | age >= 18 |
Text and dates are written between single quotes ('Paris', '2025-01-01'), numbers without.
Combining several conditions
AND: both conditions must be true.OR: at least one of them must be true.NOT: reverses a condition.
AND is evaluated before OR, just like multiplication before addition. As soon as you mix the two, add parentheses to be sure of what your query means.
Diagram
| prenom | ville |
|---|---|
| Léa | Lyon |
| Hugo | Paris |
| Inès | Lyon |
| Adam | Nantes |
| prenom | ville |
|---|---|
| Léa | Lyon |
| Inès | Lyon |
Simplified diagram to show the idea. The examples below use the real SQL Quest practice database (a fictional online shop: see the full schema).
Glossary: the sample database uses French names
clients- customers
commandes- orders
lignes_commande- order lines
produits- products
fournisseurs- suppliers
employes- employees
prenom / nom- first name / last name (or name)
ville- city
pays- country
prix- price
prix_unitaire- unit price
quantite- quantity
categorie- category
date_commande- order date
poste- job title
departement- department
salaire- salary
statut- status: livrée = delivered, expédiée = shipped, en cours = in progress, annulée = cancelled
Examples with their results
1. A simple condition
The customers who live in Paris.
SELECT prenom, nom, ville
FROM clients
WHERE ville = 'Paris'; Try it in the sandbox| prenom | nom | ville |
|---|---|---|
| Zoé | Laurent | Paris |
| Jade | Garcia | Paris |
| Sarah | Lambert | Paris |
| Yanis | Haddad | Paris |
| Chloé | Bonnet | Paris |
| Jade | Dubois | Paris |
| Lucas | Dubois | Paris |
| Omar | Dubois | Paris |
| Clara | Lefebvre | Paris |
| Inès | Fontaine | Paris |
13 rows in total · 10 shown
2. Comparing numbers
The products that cost less than €10.
SELECT nom, prix
FROM produits
WHERE prix < 10; Try it in the sandbox| nom | prix |
|---|---|
| Tapis de yoga | 6.53 |
| Roman policier | 8.03 |
| BD aventure | 9.98 |
| Miel bio | 3.7 |
4 rows in total
3. Two conditions with AND
The employees of the IT department who earn more than €4,000.
SELECT prenom, nom, departement, salaire
FROM employes
WHERE departement = 'IT' AND salaire > 4000; Try it in the sandbox| prenom | nom | departement | salaire |
|---|---|---|---|
| Nathan | Roux | IT | 6,800 |
| Inès | Moreau | IT | 4,500 |
| Clara | Garcia | IT | 5,100 |
3 rows in total
4. AND and OR with parentheses
The sports or home products that cost less than €15. Without the parentheses, the price condition would only apply to home products.
SELECT nom, categorie, prix
FROM produits
WHERE (categorie = 'Sport' OR categorie = 'Maison') AND prix < 15; Try it in the sandbox| nom | categorie | prix |
|---|---|---|
| Coussin | Maison | 10.86 |
| Tapis de yoga | Sport | 6.53 |
| Ballon de foot | Sport | 14.68 |
3 rows in total
Common mistakes
Forgetting the quotes around text
Without quotes, SQL thinks Paris is a column name and returns the error no such column.
SELECT * FROM clients WHERE ville = Paris;SELECT * FROM clients WHERE ville = 'Paris';Mixing AND and OR without parentheses
a OR b AND c is read as a OR (b AND c). The result is often not what you wanted.
SELECT * FROM produits WHERE categorie = 'Sport' OR categorie = 'Maison' AND prix < 15;SELECT * FROM produits WHERE (categorie = 'Sport' OR categorie = 'Maison') AND prix < 15;Comparing with = NULL
A missing value (NULL) is equal to nothing, not even to NULL. Use IS NULL (see the lesson on NULL).
SELECT * FROM clients WHERE age = NULL;SELECT * FROM clients WHERE age IS NULL;Exercises
Try writing the query yourself before opening the solution.
Challenge 1. Show the orders (all columns) whose status is “annulée” (cancelled).
Show a solution
SELECT * FROM commandes WHERE statut = 'annulée';| id | client_id | date_commande | statut | employe_id |
|---|---|---|---|---|
| 1 | 103 | 2023-06-02 | annulée | 6 |
| 13 | 77 | 2024-06-02 | annulée | 6 |
| 22 | 84 | 2023-02-03 | annulée | 25 |
| 23 | 82 | 2023-05-24 | annulée | 8 |
| 25 | 50 | 2024-09-02 | annulée | 9 |
| 27 | 18 | 2024-10-25 | annulée | 24 |
| 35 | 101 | 2025-04-07 | annulée | 14 |
| 43 | 57 | 2025-11-13 | annulée | 18 |
92 rows in total · 8 shown
Try it in the sandboxChallenge 2. Show the customers from Lyon who are under 30.
Show a solution
SELECT prenom, nom, age FROM clients WHERE ville = 'Lyon' AND age < 30;| prenom | nom | age |
|---|---|---|
| Théo | Michel | 20 |
1 row in total
Try it in the sandboxThe interactive exercises are checked automatically, with a tutor who explains your mistakes. A short lesson stays next to the editor.
Frequently asked questions
What is the difference between WHERE and HAVING?
WHERE filters rows before they are grouped; HAVING filters groups after a GROUP BY. To filter on a COUNT or a SUM, you need HAVING.
Is WHERE case-sensitive?
With =, text comparison is sensitive to case and accents in SQLite: 'paris' is not equal to 'Paris'. LIKE, on the other hand, ignores case for unaccented letters.
Can I compare two columns?
Yes, for example WHERE prix_unitaire > prix compares two columns of the same row.
How do I write “not equal to”?
With <> (standard SQL) or != (accepted by most databases, including SQLite).