Ранее мы рассматривали соединение INNER JOIN. В его результат попадают только те строки, для которых нашлась пара, удовлетворяющая условию соединения. То есть там могут быть не все строки из первой или второй таблицы. Но бывают задачи, когда мы хотим построить соединение двух таблиц, но так, чтобы в нем были все строки одной из таблиц. Такие задачи можно решать с помощью LEFT JOIN и RIGHT JOIN.
Сравниваем INNER JOIN и LEFT JOIN
Рассмотрим пример с сотрудниками и отделами компании.
Таблица departments хранит информацию об отделах:
departments
| department_id | name |
|---|---|
| 1 | Development Department |
| 2 | Marketing Department |
| 3 | Finance Department |
| 4 | HR Department |
| 5 | Sales Department |
Таблица employees хранит информацию о сотрудниках:
employees
| employee_id | department_id | name | salary |
|---|---|---|---|
| 1 | 1 | John Smith | 50000.00 |
| 2 | 1 | Peter Johnson | 60000.00 |
| 3 | 2 | Mary Brown | 55000.00 |
| 4 | 2 | Alex Miller | 70000.00 |
| 5 | 3 | Helen White | 48000.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
Результат внутреннего соединения
| department | employee |
|---|---|
| Development Department | John Smith |
| Development Department | Peter Johnson |
| Marketing Department | Mary Brown |
| Marketing Department | Alex Miller |
| Finance Department | Helen 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. Результат выполнения запроса:
| department | employee |
|---|---|
| Development Department | John Smith |
| Development Department | Peter Johnson |
| Marketing Department | Mary Brown |
| Marketing Department | Alex Miller |
| Finance Department | Helen White |
| Sales Department | NULL |
| HR Department | NULL |
View on DB Fiddle
В результате LEFT JOIN есть все строки из результата INNER JOIN, но помимо них оно содержит еще две строки — с отделом продаж и HR. В этих отделах нет сотрудников, поэтому в качестве имени сотрудника подставляется NULL-значение.
Схематично это можно представить следующим образом:
Результат содержит все строки из первой таблицы, даже те, которые не удалось связать.
Сравниваем, как работает группировка
Рассмотрим еще один пример, который подчеркивает разницу между 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
| department | employees_count |
|---|---|
| Finance Department | 1 |
| Marketing Department | 2 |
| Development Department | 2 |
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
| department | employees_count |
|---|---|
| Sales Department | 0 |
| HR Department | 0 |
| Finance Department | 1 |
| Marketing Department | 2 |
| Development Department | 2 |
View on DB Fiddle
Текст запросов также отличается только типом соединения. А результаты отличаются тем, что в запросе с INNER JOIN нет отделов с нулевым количеством сотрудников, а в запросе LEFT JOIN они есть. Разница снова связана с тем, как обрабатываются строки без пары.
RIGHT JOIN
Запрос с RIGHT JOIN работает так же, как и LEFT 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 работает похожим образом, но только в результат попадают все строки из второй таблицы, а не из первой.
Для полного доступа к курсу нужен базовый план
Базовый план откроет полный доступ ко всем курсам, упражнениям и урокам Хекслета, проектам и пожизненный доступ к теории пройденных уроков. Подписку можно отменить в любой момент.