SQL: Join

Теория: LEFT JOIN (Левое внешнее соединение)

Ранее мы рассматривали соединение INNER JOIN. В его результат попадают только те строки, для которых нашлась пара, удовлетворяющая условию соединения. То есть там могут быть не все строки из первой или второй таблицы. Но бывают задачи, когда мы хотим построить соединение двух таблиц, но так, чтобы в нем были все строки одной из таблиц. Такие задачи можно решать с помощью LEFT JOIN и RIGHT JOIN.

Сравниваем INNER JOIN и LEFT JOIN

Рассмотрим пример с сотрудниками и отделами компании.

Таблица departments хранит информацию об отделах:

departments

department_idname
1Development Department
2Marketing Department
3Finance Department
4HR Department
5Sales Department

Таблица employees хранит информацию о сотрудниках:

employees

employee_iddepartment_idnamesalary
11John Smith50000.00
21Peter Johnson60000.00
32Mary Brown55000.00
42Alex Miller70000.00
53Helen White48000.00

View on DB Fiddle

В отделах HR (department_id = 4) и Sales (department_id = 5) пока еще нет ни одного сотрудника.

Рассмотрим, как работает левое внешнее соединение в сравнении с внутренним соединением.

Начнем с внутреннего соединения:

SELECT
    dep.name AS department,
    emp.name AS employee
FROM departments AS dep
INNER JOIN employees AS emp ON -- внутреннее соединение
    dep.department_id = emp.department_id

Результат внутреннего соединения

departmentemployee
Development DepartmentJohn Smith
Development DepartmentPeter Johnson
Marketing DepartmentMary Brown
Marketing DepartmentAlex Miller
Finance DepartmentHelen White

View on DB Fiddle

А теперь рассмотрим левое внешнее соединение:

SELECT
    dep.name AS department,
    emp.name AS employee
FROM departments AS dep
LEFT JOIN employees AS emp ON -- левое внешнее соединение
    dep.department_id = emp.department_id

В тексте запроса почти нет отличий — вместо INNER указано слово LEFT. Результат выполнения запроса:

departmentemployee
Development DepartmentJohn Smith
Development DepartmentPeter Johnson
Marketing DepartmentMary Brown
Marketing DepartmentAlex Miller
Finance DepartmentHelen White
Sales DepartmentNULL
HR DepartmentNULL

View on DB Fiddle

В результате LEFT JOIN есть все строки из результата INNER JOIN, но помимо них оно содержит еще две строки — с отделом продаж и HR. В этих отделах нет сотрудников, поэтому в качестве имени сотрудника подставляется NULL-значение.

Схематично это можно представить следующим образом:

left-join

Результат содержит все строки из первой таблицы, даже те, которые не удалось связать.

Сравниваем, как работает группировка

Рассмотрим еще один пример, который подчеркивает разницу между INNER JOIN и LEFT JOIN. Допустим, мы хотим посчитать количество сотрудников в каждом из отделов. Такую задачу мы уже решали — надо воспользоваться соединением и группировкой.

Запрос с внутренним соединением

SELECT
    dep.name AS department,
    COUNT(emp.employee_id) AS employees_count
FROM departments AS dep
INNER JOIN employees AS emp ON
    dep.department_id = emp.department_id
GROUP BY dep.name
departmentemployees_count
Finance Department1
Marketing Department2
Development Department2

View on DB Fiddle

Запрос с левым внешним соединением

SELECT
    dep.name AS department,
    COUNT(emp.employee_id) AS employees_count
FROM departments AS dep
LEFT JOIN employees AS emp ON
    dep.department_id = emp.department_id
GROUP BY dep.name
departmentemployees_count
Sales Department0
HR Department0
Finance Department1
Marketing Department2
Development Department2

View on DB Fiddle

Текст запросов также отличается только типом соединения. А результаты отличаются тем, что в запросе с INNER JOIN нет отделов с нулевым количеством сотрудников, а в запросе LEFT JOIN они есть. Разница снова связана с тем, как обрабатываются строки без пары.

RIGHT JOIN

Запрос с RIGHT JOIN работает так же, как и LEFT JOIN. Но в результат попадают все строки из второй (правой) таблицы, а не из первой (левой).

Схематично работа RIGHT JOIN выглядит так:

right-join

Результат содержит все строки из второй таблицы, даже те, которые не удалось связать.

Запрос, в котором используется левое внешнее соединение, можно легко переписать на запрос с правым внешним соединением:

Запрос с левым внешним соединением

SELECT
    dep.name AS department,
    COUNT(emp.employee_id) AS employees_count
FROM departments AS dep
LEFT JOIN employees AS emp ON
    dep.department_id = emp.department_id
GROUP BY dep.name

View on DB Fiddle

Запрос с правым внешним соединением

SELECT
    dep.name AS department,
    COUNT(emp.employee_id) AS employees_count
FROM employees AS emp
RIGHT JOIN departments AS dep ON
    dep.department_id = emp.department_id
GROUP BY dep.name

View on DB Fiddle

Эти запросы отличаются только типом соединения и порядком таблиц. То есть можно сказать, что TableA LEFT JOIN TableB = TableB RIGHT JOIN TableA.

Выводы

LEFT JOIN используют, когда нужно построить соединение, в котором обязательно будут все строки из первой таблицы. Если для строки из первой таблицы нет подходящих пар во второй таблице, то вместо данных из второй таблицы будут подставлены NULL-значения.

RIGHT JOIN работает похожим образом, но только в результат попадают все строки из второй таблицы, а не из первой.

Рекомендуемые программы