Phase 1 · Reading data: SELECT, WHERE and sorting · Topic 1.4

NULL: the missing value

Must know

NULL means "no value" or "unknown"; any comparison with it — even NULL = NULL — is unknown rather than true, so you test for it with IS NULL and replace it with COALESCE.

Not started

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

AnimationNULL is "unknown": = never matches it, and <> quietly drops it
Read the animation as text
  1. NULL means "unknown". Asha has no manager, so her manager_id is NULL. How do you find her?
  2. manager_id = NULL asks "is this equal to unknown?" — and the answer is always unknown, even for Asha (unknown = unknown is still unknown).
  3. WHERE keeps only rows where the test is true. Nothing is true, so no rows come back at all — and no error tells you.
  4. 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
SQL has three answers, not two. Any with NULL is unknown, and only keeps rows whose answer is true — so rows with NULLs quietly disappear.

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

sql
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

  1. 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.
  2. WHERE manager_id IS NULL: true for Asha only. IS NULL is a real test that answers yes or no.
  3. WHERE dept_id <> 1: for Gus, NULL <> 1 is unknown, so Gus is dropped — even though he is clearly not in department 1.
  4. To keep him, say so: WHERE dept_id <> 1 OR dept_id IS NULL.
  5. 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

sql
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

sql
SELECT name, manager_id
FROM employees
WHERE manager_id IS NULL;

1 row

namemanager_id
AshaNULL

NULL quietly drops a row from "not equal"

sql
SELECT name, dept_id
FROM employees
WHERE dept_id <> 1
ORDER BY name;

3 rows

namedept_id
Dara2
Eli2
Fatima3

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

sql
SELECT order_id, amount, COALESCE(amount, 0) AS amount_or_zero
FROM orders
WHERE customer_id = 3
ORDER BY order_id;

2 rows

order_idamountamount_or_zero
106NULL0
1076060

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 = NULL or <> 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 + NULL is 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 = NULL and 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); has a <=> b.
  • COALESCE works everywhere. MySQL also has IFNULL(a, b), has ISNULL(a, b), and Oracle has NVL(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.

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.

  1. ExplainSay what it does and when to use it, in plain words, with no notes.

    Explain three-valued logic, and why WHERE manager_id = NULL returns 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 = NULL asks "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.

  2. 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.

    sql
    SELECT name, city
    FROM customers
    WHERE city IS NULL;

    1 row

    namecity
    ZoeNULL
  3. 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.

    sql
    SELECT NULL = NULL, NULL IS NULL, 5 + NULL, COALESCE(NULL, NULL, 7);

    1 row

    NULL = NULLNULL IS NULL5 + NULLCOALESCE(NULL, NULL, 7)
    NULL1NULL7
  4. 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 <> 1 alone misses Gus, because NULL <> 1 is unknown. Add the NULL case on purpose with OR dept_id IS NULL.

    Other ways that also work: COALESCE(dept_id, 0) <> 1, or dept_id IS NOT 1 in SQLite (IS DISTINCT FROM 1 in PostgreSQL).

    sql
    SELECT name, dept_id
    FROM employees
    WHERE dept_id <> 1 OR dept_id IS NULL
    ORDER BY name;

    4 rows

    namedept_id
    Dara2
    Eli2
    Fatima3
    GusNULL

Practice box: write and run your answers here

Ctrl/⌘ + Enter runs it. Select part of the query to run only that part.

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.