Lesson 7 — Filtering Rows
WHERE
WHERE filters which rows appear in your results. It supports comparison, range, pattern, list, and null tests — mastering all of them gives you precise control over your data.
SQL — Basic WHERE
-- Basic comparisons:
SELECT full_name, mark FROM learners WHERE mark >= 50;
SELECT full_name, city FROM learners WHERE city = 'Johannesburg';
SELECT full_name, mark FROM learners WHERE mark <> 50; -- not equal (<> or !=)
SELECT full_name, age FROM learners WHERE age < 25;
-- Multiple conditions with AND / OR:
SELECT full_name, mark
FROM learners
WHERE mark >= 50 AND city = 'Johannesburg';
SELECT full_name, city
FROM learners
WHERE city = 'Cape Town' OR city = 'Durban';
-- NOT:
SELECT full_name FROM learners WHERE NOT city = 'Johannesburg';
SQL — BETWEEN and IN
-- BETWEEN — inclusive range (same as >= AND <=):
SELECT full_name, mark
FROM learners
WHERE mark BETWEEN 60 AND 80;
-- Equivalent to: WHERE mark >= 60 AND mark <= 80
-- BETWEEN with dates:
SELECT full_name, enrolment_date
FROM learners
WHERE enrolment_date BETWEEN '2024-01-01' AND '2024-12-31';
-- IN — match any value in a list:
SELECT full_name, course
FROM learners
WHERE course IN ('Java', 'Python', 'C#');
-- NOT IN:
SELECT full_name, course
FROM learners
WHERE course NOT IN ('SQL', 'Undecided');
SQL — LIKE patterns
-- LIKE — pattern matching:
-- % matches zero or more characters
-- _ matches exactly one character
SELECT full_name FROM learners
WHERE full_name LIKE 'T%'; -- starts with T
SELECT full_name FROM learners
WHERE full_name LIKE '%Mokoena'; -- ends with Mokoena
SELECT full_name FROM learners
WHERE full_name LIKE '%an%'; -- contains 'an' anywhere
SELECT email FROM learners
WHERE email LIKE '%@gmail.com'; -- Gmail addresses
SELECT phone FROM learners
WHERE phone LIKE '082_______'; -- 082 followed by exactly 7 digits
-- Case sensitivity:
-- MySQL LIKE is case-insensitive by default for latin charset
-- PostgreSQL LIKE is case-sensitive; use ILIKE for case-insensitive
SQL — NULL checks
-- NULL checks:
SELECT full_name FROM learners WHERE mark IS NULL; -- not yet marked
SELECT full_name FROM learners WHERE mark IS NOT NULL; -- has a mark
-- NEVER use = NULL or != NULL — they never return rows:
-- WHERE mark = NULL -- always returns 0 rows (NULL is not equal to anything)
-- WHERE mark != NULL -- always returns 0 rows
-- COALESCE — use a default when NULL:
SELECT full_name,
COALESCE(mark, 0) AS mark_or_zero
FROM learners;
Practice Task
Your Turn
Write queries: (1) learners with mark between 70 and 90; (2) learners from Johannesburg or Pretoria; (3) learners enrolled in Java OR Python but NOT SQL; (4) learners whose name starts with 'S'; (5) learners who have no city on record (IS NULL); (6) learners aged 18-25 with a mark above 60 and from Gauteng.
Common Mistakes
WHERE mark = NULLreturns nothing — always useIS NULL.LIKE '%text%'cannot use an index efficiently — slow on large tables.NOT INwith a subquery that can return NULL — the result is always empty. UseNOT EXISTSinstead.- AND binds tighter than OR — use parentheses:
WHERE (city='JHB' OR city='CPT') AND mark >= 50notWHERE city='JHB' OR city='CPT' AND mark >= 50.
Professional Tip
BETWEEN is inclusive on both ends. BETWEEN 60 AND 80 includes both 60 and 80. If you want to exclude an endpoint, use explicit >= and < comparisons.
Mini Quiz
How do you correctly check for NULL in a WHERE clause?
NULL represents unknown, and unknown = unknown is not true or false — it is unknown. You must use IS NULL or IS NOT NULL for null checks.