Step 1 Understand it
Why you need it. Real data has gaps: an employee with no manager, an order with no amount. causes more wrong answers than anything else in , because it doesn't behave like a normal value. quietly vanish from filters, and sums and averages change, without any error message.
New words in this topic (tap one to see what it means)
Watch it happen
Read the animation as text
- NULL means "unknown". Asha has no manager, so her manager_id is NULL. How do you find her?
- manager_id = NULL asks "is this equal to unknown?" — and the answer is always unknown, even for Asha (unknown = unknown is still unknown).
- WHERE keeps only rows where the test is true. Nothing is true, so no rows come back at all — and no error tells you.
- IS NULL is a real yes/no test. It is true for Asha only: Asha.
Picture it
flowchart LR C["a condition<br/>on one row"] --> T["true"] C --> F["false"] C --> U["unknown<br/>anything compared with NULL"] T -->|"WHERE keeps"| K["kept"] F -->|"WHERE drops"| D["dropped"] U -->|"WHERE drops"| D
The idea
NULL is not zero and not empty text; it means "we don't know". So SQL uses : a condition can be true, false or unknown. manager_id = NULL is unknown for every row — even a NULL one, because "is this unknown thing equal to that unknown thing?" is itself unknown. WHERE keeps only true, so the returns nothing. To test for NULL, use or IS NOT NULL. Any arithmetic with NULL gives NULL (10 + NULL is NULL). COALESCE(a, b, …) returns the first value that isn't NULL, which is how you put in a default.
The shape of it
WHERE column IS NULL
WHERE column IS NOT NULL
COALESCE(column, default_value)Words in lower case are the parts you fill in.
How it works, step by step
WHERE manager_id = NULL: for Asha, NULL = NULL is unknown; for everyone else, 1 = NULL is unknown. Nothing is true, so no rows come back.WHERE manager_id IS NULL: true for Asha only. IS NULL is a real test that answers yes or no.WHERE dept_id <> 1: for Gus, NULL <> 1 is unknown, so Gus is dropped — even though he is clearly not in department 1.- To keep him, say so:
WHERE dept_id <> 1 OR dept_id IS NULL. COALESCE(amount, 0)turns order 106's NULL into 0 and leaves the other amounts alone.
Analogy
A form with a blank box for "age". Is a blank age over 30? You can't say yes, and you can't say no — you just don't know. Are two blank ages equal? You don't know that either.
Where the analogy breaks
A person looking at two blank boxes might say "they're both blank, so they match". SQL never does that with =. Only IS NULL, IS NOT DISTINCT FROM, and grouping ( puts all NULLs together) treat NULLs as alike.
Worked examples
= NULL never matches
SELECT name
FROM employees
WHERE manager_id = NULL;No rows
| name |
|---|
No error, and no rows — the most dangerous kind of bug. Asha has a NULL manager_id, but NULL = NULL is unknown, not true.
IS NULL is the right test
SELECT name, manager_id
FROM employees
WHERE manager_id IS NULL;1 row
| name | manager_id |
|---|---|
| Asha | NULL |
NULL quietly drops a row from "not equal"
SELECT name, dept_id
FROM employees
WHERE dept_id <> 1
ORDER BY name;3 rows
| name | dept_id |
|---|---|
| Dara | 2 |
| Eli | 2 |
| Fatima | 3 |
Gus is missing. His department is unknown, so "not 1" is unknown, and WHERE drops him. Add OR dept_id IS NULL to keep him.
puts in a default
SELECT order_id, amount, COALESCE(amount, 0) AS amount_or_zero
FROM orders
WHERE customer_id = 3
ORDER BY order_id;2 rows
| order_id | amount | amount_or_zero |
|---|---|---|
| 106 | NULL | 0 |
| 107 | 60 | 60 |
COALESCE returns its first argument that isn't NULL. Choose the default carefully: 0 is right for "nothing paid", but wrong if it means "we don't know".
Must-know points
- NULL means unknown or missing. It is not 0 and not ''.
- Never write
= NULLor<> NULL. Use IS NULL and IS NOT NULL. - Any comparison with NULL is unknown, and WHERE drops unknown rows — including from
<>and . - Arithmetic with NULL gives NULL:
10 + NULLis NULL. COALESCE(a, b, c)returns the first non-NULL value.NULLIF(a, b)returns NULL when a = b — handy to avoid dividing by zero.- (, AVG, of a ) skip NULLs — Phase 2 covers this.
Common mistakes
- Writing
WHERE manager_id = NULLand getting no rows, with no error. - Forgetting that
<>drops NULL rows: "everyone not in Sales" silently loses people with no department. - Replacing NULL with 0 in an average, which changes the answer. Decide what the gap really means first.
In other databases
- NULL-safe equality: and have
a IS NOT DISTINCT FROM b(true when both are NULL); hasa <=> b. - COALESCE works everywhere. MySQL also has
IFNULL(a, b), hasISNULL(a, b), and Oracle hasNVL(a, b)— all for two arguments. - In Oracle, empty text '' is treated as NULL. No other major does this.
Step 2 Go further (free, optional)
Optional. The notes above are written to be enough on their own. These free resources give a second explanation and more practice.
-
Read
short page with a try-it editor, free
-
Read
a free interactive book
-
Practice
SQLBolt — Lesson 8: A short note on NULLs
interactive exercises in the browser, free
Step 3 Practise
Try each one yourself first: out loud, or written and run in the practice box below, which saves every query you run. Then open the answer and compare.
-
ExplainSay what it does and when to use it, in plain words, with no notes.
Explain three-valued logic, and why
WHERE manager_id = NULLreturns no rows.Show answer
In SQL a condition can be true, false or unknown. That is three-valued logic. Any comparison with NULL is unknown, because you can't compare against a value nobody knows.
WHERE manager_id = NULLasks "is manager_id equal to unknown?" for each row. The answer is unknown every time, even for Asha, whose manager_id really is NULL. WHERE keeps only rows that are true, so no rows come back.To find missing values, ask a different question:
WHERE manager_id IS NULL. IS NULL is always true or false, never unknown. -
Writefrom a blank page, then run it
Write a query for customers with no city on record, showing name and city.
Show answer
Use IS NULL, never
= NULL. Only Zoe has no city.sqlSELECT name, city FROM customers WHERE city IS NULL;1 row
name city Zoe NULL -
Predictsay it before you run it
What do
SELECT NULL = NULL, NULL IS NULL, 5 + NULL, COALESCE(NULL, NULL, 7);return? Say all four.Show answer
NULL, 1 (true), NULL, 7.
•
NULL = NULL: two unknowns can't be called equal, so it is unknown: NULL.
•NULL IS NULL: true, which SQLite shows as 1.
•5 + NULL: any sum with NULL is NULL.
•COALESCE(NULL, NULL, 7): the first value that is not NULL, which is 7.sqlSELECT NULL = NULL, NULL IS NULL, 5 + NULL, COALESCE(NULL, NULL, 7);1 row
NULL = NULL NULL IS NULL 5 + NULL COALESCE(NULL, NULL, 7) NULL 1 NULL 7 -
Edge casesSay what happens with NULLs, ties, duplicates or no rows at all, and fix it.
Write "every employee not in department 1", making sure Gus is included.
Show answer
dept_id <> 1alone misses Gus, becauseNULL <> 1is unknown. Add the NULL case on purpose withOR dept_id IS NULL.Other ways that also work:
COALESCE(dept_id, 0) <> 1, ordept_id IS NOT 1in SQLite (IS DISTINCT FROM 1in PostgreSQL).sqlSELECT name, dept_id FROM employees WHERE dept_id <> 1 OR dept_id IS NULL ORDER BY name;4 rows
name dept_id Dara 2 Eli 2 Fatima 3 Gus NULL
Practice box: write and run your answers here
Your queries in this box
Step 4 Interview-ready, then prove it
Your interview answer
About 20 to 40 seconds, said out loud.
NULL represents a missing or unknown value, and SQL uses three-valued logic: comparisons with NULL return unknown, and WHERE keeps only rows that are true. So I never compare with equals NULL — I use IS NULL or IS NOT NULL — and I watch for filters like not-equal or NOT IN silently dropping NULL rows. When I need a default I use COALESCE, but only after deciding whether the gap really means zero.
Follow-up questions
What does NULL = NULL return?
NULL (unknown), not true. Use IS NULL, or IS NOT DISTINCT FROM to compare two values that might both be NULL.
Does COUNT(*) count NULLs?
COUNT(*) counts rows, so yes. COUNT(column) counts only the rows where that column is not NULL.
How do you avoid dividing by zero?
Wrap the divisor in : a / NULLIF(b, 0) returns NULL instead of an error when b is 0.
Tick each check when you can do it without notes
A topic is finished when you pass all four checks, not when you have read it. Be strict: if you had to look at the notes, it is not ticked yet.
- Explain Say what it does and when to use it, in plain words, with no notes.
- Write Write the query from a blank page, then run it to check.
- Predict Read a query and say which rows it returns before you run it.
- Edge cases Say what happens with NULLs, ties, duplicates or no rows at all, and fix it.
0 of 4 checks ticked.
Saved in this browser. Back it up or move it to another device.