Skip to main content
eLearner.app
Module 4 · Lesson 2 of 414/57 in the course~10 min
Module lessons (2/4)

Handling NULLs: IS NULL and COALESCE

In the employees dataset, Andrea Costa is special: he has department_id = NULL. You have already brushed against NULL (with LEFT JOIN), but the time has come to take it seriously: NULLs in SQL behave differently from any other value, and ignoring them is one of the top causes of bugs in production code.

NULL is not zero, not empty string

NULL means unknown / missing value. It is not 0, not '', not false. It is "I don't know". From this follows a surprising property: NULL is not equal to anything, not even itself.

SQL
-- All these expressions return NULL (not true!):
SELECT NULL = NULL;       -- NULL
SELECT NULL = 0;          -- NULL
SELECT NULL <> 'qualcosa'; -- NULL

Concrete consequence: WHERE column = NULL never works. You must use the dedicated operators IS NULL / IS NOT NULL:

SQL
-- Employees without a department:
SELECT first_name, last_name
FROM   employees
WHERE  department_id IS NULL;

-- Employees WITH a department:
SELECT first_name, last_name
FROM   employees
WHERE  department_id IS NOT NULL;

COALESCE — the NULL fallback

Often you want to display something instead of NULL when the data is missing: the string '(none)', zero, a default date. The function that does exactly this is COALESCE(a, b, c, ...): it returns the first non-NULL argument in the list.

SQL
-- Show the department_id, or 0 if missing:
SELECT first_name, last_name, COALESCE(department_id, 0) AS dept
FROM   employees;

Combined with a LEFT JOIN it becomes incredibly powerful for reports:

SQL
SELECT e.first_name,
       e.last_name,
       COALESCE(d.name, '(nessun dipartimento)') AS dipartimento
FROM   employees   AS e
LEFT JOIN departments AS d ON e.department_id = d.id;

Result: all employees returned, with the department name or an explicit label for those who do not have one.

NULL and aggregates

Aggregate functions ignore NULLs (except COUNT(*)):

  • COUNT(department_id) counts only the rows with a value;
  • AVG(salary) averages ignoring NULLs — it does not treat them as 0;
  • SUM(...) sums only the non-NULL values.

This is almost always what you want. But it is good to know: if you are looking for "the total number of employees" use COUNT(*), not COUNT(department_id).

Try it

Exercise#sql.m4.l2.e1
Attempts: 0Loading…

For every employee, show first name (first_name), last name (last_name) and a column 'dipartimento_id' which equals their department_id or -1 if not assigned. Three columns, one row per employee.

Loading editor…
Show hint

Use COALESCE(department_id, -1) to replace NULLs with -1.

Solution available after 3 attempts

Review exercise

Exercise#sql.m4.l2.e2
Attempts: 0Loading…

Return first name (first_name), last name (last_name) and department name (departments.name) of ALL employees, showing '(nessuno)' when the department is missing. Use LEFT JOIN + COALESCE.

Loading editor…
Show hint

COALESCE(d.name, '(nessuno)') handles the NULL introduced by the LEFT JOIN.

Solution available after 3 attempts