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

Keeping everything on the left: LEFT JOIN

The INNER JOIN from the previous lesson has an important side effect: it drops rows that have no match. If an employee has no department (department_id is NULL), they disappear from the result.

Sometimes that's what you want. Often, though, it isn't: in an HR report it's essential to see all employees, including those without a department, and know who they are. That's what LEFT JOIN is for (in full, LEFT OUTER JOIN).

How it works

SQL
SELECT columns
FROM   table_a
LEFT JOIN table_b ON table_a.x = table_b.y;

Read in English: "keep all rows of table_a; for each one try to attach a row from table_b; if there's no match, fill the columns from table_b with NULL".

The key word is LEFT: it means "left table", i.e. the one written after FROM. All of its rows survive, always.

SQL
-- All employees, including those without a department:
SELECT e.first_name,
       e.last_name,
       d.name AS dipartimento
FROM   employees   AS e
LEFT JOIN departments AS d ON e.department_id = d.id;

In our dataset this query returns 10 rows (one employee each). Andrea Costa, who has department_id = NULL, appears with dipartimento = NULL instead of disappearing.

Finding the "no match" rows

A very useful consequence: by filtering with IS NULL on a column of the right-hand table you find exactly the rows with no match:

SQL
-- Orphan employees: no department assigned
SELECT e.first_name, e.last_name
FROM   employees   AS e
LEFT JOIN departments AS d ON e.department_id = d.id
WHERE  d.id IS NULL;

This trick is used all the time in the real world: "find me orders with no customer", "products with no reviews", "users who have never logged in".

Try it

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

Return first name (first_name) and last name (last_name) of employees who do NOT have a department assigned. One or more rows, two columns.

Loading editor…
Show hint

Complete the WHERE with d.id IS NULL — you want the rows where the LEFT JOIN didn't find a matching department.

Solution available after 3 attempts

Review exercise

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

List all departments (departments.name) and next to them the number of employees, also including departments with no employees (show 0 for those). Hint: start from departments and do a LEFT JOIN with employees, then GROUP BY + COUNT.

Loading editor…
Show hint

Use COUNT(e.id) (not COUNT(*)) to count 0 when there's no match: COUNT(*) would count 1 because of the LEFT JOIN row with NULL.

Solution available after 3 attempts