MySQL WHERE Clause
The WHERE clause filters rows. It contains a condition, and only rows for which the condition is TRUE are returned, updated or deleted. Almost every real query has one, so mastering WHERE is essential.
1. How WHERE Works
SELECT columns FROM table WHERE condition;
UPDATE table SET ... WHERE condition;
DELETE FROM table WHERE condition;
Table: students (7 rows)
| id | name | city | age | course | fee_paid | joined |
|---|---|---|---|---|---|---|
| 1 | Arjun | Pune | 27 | Java | 45000.00 | 2025-07-01 |
| 2 | Beena | Delhi | 31 | Python | 38000.00 | 2025-08-15 |
| 3 | Chirag | Pune | 22 | Java | 20000.00 | 2025-09-03 |
| 4 | Deepa | Pune | NULL | Data Science | 52000.00 | 2025-11-20 |
| 5 | Eli | Pune | 35 | Python | 38000.00 | 2026-01-10 |
| 6 | Farhan | Mumbai | 24 | Java | 0.00 | 2026-02-02 |
| 7 | Gauri | Delhi | 29 | Data Science | 52000.00 | 2026-02-18 |
2. Comparison Operators
| Operator | Meaning | Example |
|---|---|---|
= | equal | city = 'Pune' |
<> or != | not equal | course <> 'Java' |
>, < | greater / less than | age > 25 |
>=, <= | greater / less or equal | fee_paid >= 40000 |
<=> | NULL-safe equal | age <=> NULL |
SELECT name, course, fee_paid FROM students WHERE fee_paid >= 40000;
Result: 3 rows
| name | course | fee_paid |
|---|---|---|
| Arjun | Java | 45000.00 |
| Deepa | Data Science | 52000.00 |
| Gauri | Data Science | 52000.00 |
SELECT name, city FROM students WHERE city <> 'Pune';
Result: 3 rows
| name | city |
|---|---|
| Beena | Delhi |
| Farhan | Mumbai |
| Gauri | Delhi |
3. Combining Conditions: AND, OR, NOT
SELECT name, city, age FROM students WHERE city = 'Pune' AND age >= 25;
Result: 2 rows
| name | city | age |
|---|---|---|
| Arjun | Pune | 27 |
| Eli | Pune | 35 |
SELECT name, course FROM students WHERE course = 'Python' OR city = 'Mumbai';
Result: 3 rows
| name | course |
|---|---|
| Beena | Python |
| Eli | Python |
| Farhan | Java |
AND is evaluated before OR, so use parentheses to say what you mean:
SELECT name, city, course FROM students
WHERE (city = 'Pune' OR city = 'Delhi') AND course = 'Data Science';
Result: 2 rows
| name | city | course |
|---|---|---|
| Deepa | Pune | Data Science |
| Gauri | Delhi | Data Science |
Details: AND, OR, NOT, AND with OR.
4. IN, BETWEEN and LIKE
SELECT name, course FROM students WHERE course IN ('Java', 'Python');
Result: 5 rows
| name | course |
|---|---|
| Arjun | Java |
| Beena | Python |
| Chirag | Java |
| Eli | Python |
| Farhan | Java |
SELECT name, age FROM students WHERE age BETWEEN 25 AND 30;
Result: 2 rows
| name | age |
|---|---|
| Arjun | 27 |
| Gauri | 29 |
SELECT name FROM students WHERE name LIKE '%a'; -- names ending in 'a'
Result: 2 rows
| name |
|---|
| Beena |
| Deepa |
5. NULL in WHERE
Deepa's age is unknown (NULL). A comparison with NULL is never TRUE, so neither of these finds her:
SELECT name FROM students WHERE age = NULL;
Result: Empty set (0 rows)
| name |
|---|
| No rows |
SELECT COUNT(*) AS rows_found FROM students WHERE age > 20 OR age <= 20;
Result: 1 row
| rows_found |
|---|
| 6 |
Seven students, but only six counted: NULL is neither above nor below 20. Use IS NULL:
SELECT name FROM students WHERE age IS NULL;
Result: 1 row
| name |
|---|
| Deepa |
6. Filtering Dates
SELECT name, joined FROM students WHERE joined >= '2026-01-01';
Result: 3 rows
| name | joined |
|---|---|
| Eli | 2026-01-10 |
| Farhan | 2026-02-02 |
| Gauri | 2026-02-18 |
SELECT name, joined FROM students
WHERE joined >= '2025-08-01' AND joined < '2025-12-01'; -- Aug to Nov 2025
Result: 3 rows
| name | joined |
|---|---|
| Beena | 2025-08-15 |
| Chirag | 2025-09-03 |
| Deepa | 2025-11-20 |
WHERE YEAR(joined) = 2026 gives the same rows but stops MySQL using an index on joined.7. Expressions and Functions in WHERE
SELECT name, fee_paid FROM students WHERE fee_paid / 1000 > 45;
Result: 2 rows
| name | fee_paid |
|---|---|
| Deepa | 52000.00 |
| Gauri | 52000.00 |
SELECT name, city FROM students WHERE UPPER(LEFT(name, 1)) IN ('A', 'E', 'I', 'O', 'U');
Result: 2 rows
| name | city |
|---|---|
| Arjun | Pune |
| Eli | Pune |
8. Sub-queries in WHERE
SELECT name, course, fee_paid
FROM students
WHERE fee_paid > (SELECT AVG(fee_paid) FROM students);
Result: 5 rows
| name | course | fee_paid |
|---|---|---|
| Arjun | Java | 45000.00 |
| Beena | Python | 38000.00 |
| Deepa | Data Science | 52000.00 |
| Eli | Python | 38000.00 |
| Gauri | Data Science | 52000.00 |
SELECT name, city FROM students
WHERE city IN (SELECT city FROM students GROUP BY city HAVING COUNT(*) >= 2);
Result: 6 rows
| name | city |
|---|---|
| Arjun | Pune |
| Beena | Delhi |
| Chirag | Pune |
| Deepa | Pune |
| Eli | Pune |
| Gauri | Delhi |
9. WHERE in UPDATE and DELETE
The same conditions choose which rows change. Preview with SELECT, then run the change:
SELECT name, fee_paid FROM students WHERE fee_paid = 0;
UPDATE students SET fee_paid = 15000 WHERE fee_paid = 0;
SELECT name, fee_paid FROM students WHERE id = 6;
Preview
| name | fee_paid |
|---|---|
| Farhan | 0.00 |
After the UPDATE
| name | fee_paid |
|---|---|
| Farhan | 15000.00 |
10. Making WHERE Fast with Indexes
An index on a filtered column lets MySQL jump straight to matching rows. The condition must use the column directly (a sargable condition):
CREATE INDEX idx_joined ON students (joined);
EXPLAIN SELECT name FROM students WHERE joined >= '2026-01-01';
EXPLAIN SELECT name FROM students WHERE YEAR(joined) = 2026;
Bare column: uses the index (range)
| type | key | rows | Extra |
|---|---|---|---|
| range | idx_joined | 3 | Using index condition |
Function on the column: full scan (ALL)
| type | key | rows | Extra |
|---|---|---|---|
| ALL | NULL | 7 | Using where |
11. Practice Exercises
Exercise 1: Java or Data Science students who paid at least 45,000.
SELECT name, course, fee_paid FROM students
WHERE course IN ('Java', 'Data Science') AND fee_paid >= 45000;
Result: 3 rows
| name | course | fee_paid |
|---|---|---|
| Arjun | Java | 45000.00 |
| Deepa | Data Science | 52000.00 |
| Gauri | Data Science | 52000.00 |
Exercise 2: Students not from Pune whose age is known.
SELECT name, city, age FROM students WHERE city <> 'Pune' AND age IS NOT NULL;
Result: 3 rows
| name | city | age |
|---|---|---|
| Beena | Delhi | 31 |
| Farhan | Mumbai | 24 |
| Gauri | Delhi | 29 |
12. Summary
- WHERE keeps rows whose condition is TRUE; FALSE and NULL rows are dropped.
- Use comparison operators, AND/OR/NOT (with parentheses), IN, BETWEEN, LIKE and IS NULL.
- Never test NULL with
=; useIS NULL. - Keep indexed columns bare in conditions so indexes can be used.
- The same WHERE works in SELECT, UPDATE and DELETE.