SQL NULL Handling and COALESCE Explained
NULL means "no value" or "unknown", and it follows its own rules: it is never equal to anything, not even another NULL, and most functions skip it. Many wrong interview answers come from a single NULL quietly removing rows or changing a count.
Examples run in MySQL 8 and PostgreSQL · Updated
In short
- Any comparison with
NULLis unknown, soWHEREdrops the row. COALESCE(a, b, …)returns the first value that is not NULL.COUNT(col),SUMandAVGignore NULLs;COUNT(*)does not.NULLIF(x, 0)turns a zero into NULL, a safe way to avoid division by zero.
Three-valued logic
SQL conditions can be true, false or unknown. manager_id <> 1 is unknown for an employee whose manager_id is NULL, and WHERE keeps only rows where the condition is true. So rows with NULLs disappear from both = 1 and <> 1.
To include them, say so explicitly: manager_id <> 1 OR manager_id IS NULL.
Replacing NULLs
COALESCE takes any number of arguments and returns the first non-NULL one. It is the portable choice; MySQL also has IFNULL(a, b), which only takes two arguments and does not exist in PostgreSQL.
NULLIF(a, b) does the opposite: it returns NULL when a = b. Dividing by NULLIF(count, 0) returns NULL instead of an error when the count is zero.
The example tables
Every example on this page uses these tables. They are small on purpose, so you can check each result by eye.
employees
| emp_id | name | dept_id | salary | manager_id | hire_date |
|---|---|---|---|---|---|
| 1 | Aarav | 10 | 95000 | NULL | 2021-03-01 |
| 2 | Diya | 10 | 88000 | 1 | 2022-06-15 |
| 3 | Kabir | 10 | 72000 | 1 | 2023-01-10 |
| 4 | Meera | 20 | 64000 | NULL | 2020-11-20 |
| 5 | Rohan | 20 | 58000 | 4 | 2024-02-05 |
| 6 | Isha | 30 | 61000 | NULL | 2022-09-12 |
| 7 | Arjun | 20 | 64000 | 4 | 2023-07-30 |
| 8 | Zoya | NULL | 52000 | NULL | 2024-05-01 |
departments
| dept_id | dept_name |
|---|---|
| 10 | Engineering |
| 20 | Sales |
| 30 | Marketing |
| 40 | Finance |
Examples
Fill in a missing value
Zoya has no department, so the left join gives NULL; COALESCE shows a readable label instead.
SELECT e.name, COALESCE(d.dept_name, 'Unassigned') AS department
FROM employees e
LEFT JOIN departments d ON e.dept_id = d.dept_id
ORDER BY e.emp_id;| name | department |
|---|---|
| Aarav | Engineering |
| Diya | Engineering |
| Kabir | Engineering |
| Meera | Sales |
| Rohan | Sales |
| Isha | Marketing |
| Arjun | Sales |
| Zoya | Unassigned |
Counting with NULLs
Eight employees, but only four have a manager, and those four share two different managers.
SELECT COUNT(*) AS all_rows,
COUNT(manager_id) AS with_manager,
COUNT(DISTINCT manager_id) AS managers
FROM employees;| all_rows | with_manager | managers |
|---|---|---|
| 8 | 4 | 2 |
The not-equal trap
This looks like "everyone not managed by Aarav", but employees without a manager vanish too, because NULL <> 1 is unknown.
SELECT name, manager_id
FROM employees
WHERE manager_id <> 1
ORDER BY emp_id;| name | manager_id |
|---|---|
| Rohan | 4 |
| Arjun | 4 |
Including the NULLs on purpose
Adding OR manager_id IS NULL brings back the four employees without a manager.
SELECT name, manager_id
FROM employees
WHERE manager_id <> 1 OR manager_id IS NULL
ORDER BY emp_id;| name | manager_id |
|---|---|
| Aarav | NULL |
| Meera | NULL |
| Rohan | 4 |
| Isha | NULL |
| Arjun | 4 |
| Zoya | NULL |
Common mistakes
- Comparing with = NULL. Always use
IS NULLorIS NOT NULL. - NOT IN with a NULL in the list.
x NOT IN (1, NULL)is never true, so the query returns nothing. UseNOT EXISTS, or filter NULLs out of the subquery. - Averages that skip NULLs.
AVG(bonus)divides by the number of non-NULL bonuses. If missing should count as zero, useAVG(COALESCE(bonus, 0)).
Practise NULL & COALESCE
Interview questions that use this concept, easiest first. Each one has the step-by-step visualizer and answer checking.
Inactive 2024 Signups
List customers who registered in 2024 but have never made a purchase.
Second Highest Delivery Fee
Return the second-highest distinct delivery fee, or NULL if there isn't one.
Authors With Five Published Books
Find authors who have at least five published books in the catalog.
Units Sold per Department
Report total units sold for every department, including departments with no sales.
Listing Booking Windows
Count each listing's bookings in the last 90 days, the last 365 days and all time.
Monthly Listing Ratings
Average star rating for each listing in each month.
Want a full set? Work through the SQL Basics study plan.
Questions people ask
- Is COALESCE the same as IFNULL?
- For two arguments they behave alike, but COALESCE accepts any number of arguments and works in both MySQL and PostgreSQL; IFNULL is MySQL only.
- Are NULLs equal in GROUP BY and DISTINCT?
- Yes. Although NULL = NULL is unknown in a WHERE clause, GROUP BY and DISTINCT treat all NULLs as one group.