9 NULLs
NULL is SQL’s marker for unknown or missing. It is not zero, not the empty string, and not equal to anything — not even to another NULL. This three-valued logic (true, false, unknown) is the source of more SQL bugs than any other feature, but the rules are simple once you know them.
What you’ll learn
- What
NULLrepresents - Testing for
NULLwithIS NULL/IS NOT NULL - How
NULLpropagates through expressions and comparisons - How
NULLbehaves inAND/OR(three-valued logic) - Replacing
NULLwithCOALESCEandNULLIF
Example
= NULL does not work because the comparison evaluates to NULL, which is not TRUE, so the WHERE discards the row. The same applies to <>, <, >, IN, BETWEEN, and so on — almost any operator returns NULL when either operand is NULL. The exceptions are IS NULL, IS NOT NULL, IS DISTINCT FROM, and IS NOT DISTINCT FROM (the last two are NULL-aware versions of <> and =).
COALESCE(a, b, c) returns the first argument that is not NULL. It is the standard way to provide defaults: COALESCE(nickname, first_name, 'Anonymous'). NULLIF(a, b) returns NULL when a = b — handy when you want to turn sentinel values back into NULL (e.g. NULLIF(comment, '')).
The three-valued logic table is short and worth memorizing: TRUE OR NULL is TRUE (we know at least one side is true), but TRUE AND NULL is NULL (we don’t know the other side). FALSE AND NULL is FALSE (one false is enough). FALSE OR NULL is NULL.
Run the example
To run:
Common pitfalls
- Forgetting that aggregates skip NULL:
SUM,AVG,MIN,MAX,COUNT(col)ignore NULL inputs.COUNT(*)counts every row including those with NULLs. NOT IN (subquery)becomes the empty result if the subquery returns a single NULL — becausex <> NULLisNULL. PreferNOT EXISTS.NULL <> NULLis unknown (NULL), not true.DISTINCTgroups NULLs together;IS DISTINCT FROMprovides a comparison that always returns true or false.- Default ordering:
ORDER BY col ASCputs NULLs last;DESCputs them first. SpecifyNULLS FIRST/NULLS LASTfor predictable behavior.
When you really want NULL-aware equality, use IS NOT DISTINCT FROM. For example, WHERE a IS NOT DISTINCT FROM b is true when both are equal or both are NULL.
Run SELECT 1 = NULL;, then SELECT 1 IS NOT NULL;, then SELECT NULL IS NOT DISTINCT FROM NULL;. See how the answers differ. Then try SELECT count(*) AS rows, count(b) AS non_null_b FROM (VALUES (1, NULL), (2, 'x')) AS t(a, b);.
Downloads
SQL file: nulls.sql · All lesson files · Setup guide