Understanding NULL: IS NULL, IS NOT NULL, Empty vs Blank
Learn what NULL really means, where NULLs come from, how to find them with IS NULL / IS NOT NULL, how they behave in joins, and how NULL differs from '' and ' '.
David Warner was not picked by any team in our data — his team is NULL. NULL is the most misunderstood value in SQL: it is not 0, not an empty string, and it doesn't even equal itself. Master it here and you will avoid a whole class of wrong reports.
Definition
NULL is a special marker meaning "no value" — the value is unknown or missing. It is not a number, not text and not zero; it is the absence of a value.
| Statement | Why |
|---|---|
| NULL is not 0 | A player with NULL runs has unknown runs (e.g. did not bat). A player with 0 runs batted and scored a duck. |
| NULL is not empty | '' is a real text value with 0 characters. NULL is no value at all. |
| NULL = NULL is not TRUE | Comparing anything with NULL gives UNKNOWN, so = and <> never match NULLs. Use IS NULL. |
SQL uses three-valued logic: a condition can be TRUE, FALSE or UNKNOWN. WHERE keeps only rows where the condition is TRUE, so UNKNOWN rows are silently dropped.
Where do NULLs come from?
| Source | Example |
|---|---|
| Missing source data | Nobody entered the value — no team for Warner (team = NULL). |
| Unmatched JOINs | LEFT / RIGHT / FULL joins fill the missing side with NULL. |
| Expressions | Any arithmetic with NULL returns NULL (5 + NULL = NULL), and NULLIF() creates NULL on purpose. |
The NULL toolkit
| Goal | Tool |
|---|---|
| Replace NULL with a value | ISNULL, COALESCE |
| Create a NULL from a value | NULLIF |
| Check for NULL | IS NULL, IS NOT NULL |
The replace/create functions have their own topic next; this topic covers the checks and NULL behaviour.
Syntax
sql
SELECT columns FROM table_name WHERE column_name IS NULL;
SELECT columns FROM table_name WHERE column_name IS NOT NULL;IS NULL returns TRUE when the value is missing. IS NOT NULL returns TRUE when the value exists. They are the only correct way to test for NULL.
Example — IS NULL: find the missing
sql
SELECT name, team
FROM player_profiles
WHERE team IS NULL;| name | team |
|---|---|
| David Warner | NULL |
Example — IS NOT NULL: keep the known
sql
SELECT name, team
FROM player_profiles
WHERE team IS NOT NULL;| name | team |
|---|---|
| Virat Kohli | RCB |
| Rohit Sharma | MI |
| Jos Buttler | RR |
| MS Dhoni | CSK |
| Jasprit Bumrah | MI |
Warner is crossed out because he has no value. (player_profiles is our copy of the PDF's chapter-7 players table, with the NULL team for Warner.)
The = NULL trap
WHERE team = NULL returns no rows at all, because team = NULL is UNKNOWN for every row. Even worse, WHERE team <> 'MI' silently drops Warner too:
sql
SELECT name, team
FROM player_profiles
WHERE team <> 'MI';| name | team |
|---|---|
| Virat Kohli | RCB |
| Jos Buttler | RR |
| MS Dhoni | CSK |
Warner's NULL <> 'MI' is UNKNOWN, not TRUE. To include him: WHERE team <> 'MI' OR team IS NULL.
JOINs & NULL
NULL never equals NULL, so NULL keys do not match in a join. Suppose table A has (Kohli, RCB) and (Warner, NULL), and table B has (RCB, 'Royal Challengers') and (NULL, 'Unassigned pool').
| Join condition | Rows returned |
|---|---|
ON a.team = b.team (plain) | only Kohli — the NULL rows are lost |
ON COALESCE(a.team, '?') = COALESCE(b.team, '?') (NULL-safe) | Kohli and Warner → 'Unassigned pool' |
Plain join result:
| name | a_team | b_team | label |
|---|---|---|---|
| Kohli | RCB | RCB | Royal Challengers |
NULL-safe join result:
| name | a_team | b_team | label |
|---|---|---|---|
| Kohli | RCB | RCB | Royal Challengers |
| Warner | NULL | NULL | Unassigned pool |
COALESCE turns both NULLs into the same placeholder '?', and '?' = '?' is TRUE.
NULL vs empty vs blank
Three things that look the same on screen — but are not:
| NULL | '' (empty string) | ' ' (blank spaces) | |
|---|---|---|---|
| Meaning | no value / unknown | text with 0 characters | text containing only spaces |
IS NULL? | TRUE | FALSE | FALSE |
DATALENGTH | NULL | 0 | 3 |
LEN | NULL | 0 | 0 (trailing spaces ignored) |
Clean your data before analysing it, so all three become one consistent value:
sql
NULLIF(TRIM(team), '') -- blanks and empty text become NULL
COALESCE(NULLIF(TRIM(team), ''), 'Unsold') -- then replace with a defaultTRIM turns ' ' into ''; NULLIF(…, '') turns '' into NULL; COALESCE replaces NULL with 'Unsold'.
Common mistakes
- ❌
WHERE team = NULL→ ✅WHERE team IS NULL. - ❌
WHERE team <> 'MI'expecting NULL rows too → ✅ addOR team IS NULL. - ❌ Treating NULL runs as 0 in averages without thinking —
AVGignores NULLs; replacing them with 0 changes the answer. - ❌ Checking only
IS NULLon imported text — empty''and blank' 'values slip through. ✅NULLIF(TRIM(col), '') IS NULL.
Interview tip
Q: Why does SELECT * FROM players WHERE team NOT IN ('MI', NULL) return no rows?
NOT IN expands to team <> 'MI' AND team <> NULL. The second part is always UNKNOWN, so the whole condition is never TRUE. Avoid NULLs inside NOT IN lists (or use NOT EXISTS).
Key points to remember
- NULL means no value — unknown or missing. It is not 0 and not an empty string.
- Any comparison with NULL (=, <>, >) gives UNKNOWN, and WHERE keeps only TRUE rows.
- Always test with IS NULL / IS NOT NULL — never = NULL.
- NULLs come from missing data, unmatched outer joins, and expressions (5 + NULL = NULL).
- NULL keys never match in a join; COALESCE both sides to a placeholder for a NULL-safe join.
- NULL, '' (empty) and ' ' (blank) are different: only NULL is IS NULL.
- Clean text with COALESCE(NULLIF(TRIM(col), ''), 'default').
Try it yourself
IS NULL and IS NOT NULL
Runs on a fresh IPL practice database in your browser · edit the query and press Ctrl + Enter
The = NULL trap
Runs on a fresh IPL practice database in your browser · edit the query and press Ctrl + Enter
Plain join vs NULL-safe join
This example runs a small setup step first — click to see it
CREATE TABLE squad_a (name VARCHAR(30), team VARCHAR(10));
CREATE TABLE labels_b (team VARCHAR(10), label VARCHAR(30));
INSERT INTO squad_a VALUES ('Kohli', 'RCB'), ('Warner', NULL);
INSERT INTO labels_b VALUES ('RCB', 'Royal Challengers'), (NULL, 'Unassigned pool');Runs on a fresh IPL practice database in your browser · edit the query and press Ctrl + Enter
Practice: NULL vs empty vs blank
This example runs a small setup step first — click to see it
CREATE TABLE auction (id INT, name VARCHAR(30), team VARCHAR(10)); INSERT INTO auction VALUES (1, 'Kohli', 'RCB'), (2, 'Warner', NULL), (3, 'Smith', ''), (4, 'Root', ' ');
Runs on a fresh IPL practice database in your browser · edit the query and press Ctrl + Enter
Revision Flashcards
Tap a card to flip it and see the answer.
