Внешнее соединение OUTER JOIN

Внешнее соединение может быть трёх типов: левое (LEFT), правое (RIGHT) и полное (FULL). По умолчанию оно является полным.

Главным отличием внешнего соединения от внутреннего является то, что оно обязательно возвращает все строки одной (LEFT, RIGHT) или двух таблиц (FULL).

Внешнее левое соединение (LEFT OUTER JOIN)

Соединение, которое возвращает все значения из левой таблицы, соединённые с соответствующими значениями из правой таблицы, если они удовлетворяют условию соединения, или заменяет их на NULL в обратном случае.

Для примера получим из базы данных расписание звонков, объединённых с соответствующими занятиями в расписании занятий.

Данные в таблице Timepair (расписание звонков):

idstart_pairend_pair
108:30:0009:15:00
209:20:0010:05:00
310:15:0011:00:00
411:05:0011:50:00
512:50:0013:35:00
613:40:0014:25:00
714:35:0015:20:00
815:25:0016:10:00

Данные в таблице Schedule (расписание занятий):

iddateclassnumber_pairteachersubjectclassroom
12019-09-01T00:00:00.000Z9111147
22019-09-01T00:00:00.000Z928213
32019-09-01T00:00:00.000Z934313
42019-09-02T00:00:00.000Z914313
52019-09-02T00:00:00.000Z922434
62019-09-02T00:00:00.000Z936535
72019-09-03T00:00:00.000Z915636
82019-09-03T00:00:00.000Z9213737
92019-09-03T00:00:00.000Z936838
102019-09-04T00:00:00.000Z919939
112019-09-04T00:00:00.000Z92101040
122019-09-04T00:00:00.000Z9331141
132019-09-05T00:00:00.000Z9131343
142019-09-05T00:00:00.000Z9211147
152019-09-05T00:00:00.000Z935636
162019-08-30T00:00:00.000Z912434
172019-08-30T00:00:00.000Z928213
182019-08-30T00:00:00.000Z936535
192019-08-30T00:00:00.000Z9410147
202019-09-03T00:00:00.000Z94101040
212019-08-30T00:00:00.000Z817953
222019-08-30T00:00:00.000Z827953
232019-08-30T00:00:00.000Z838238
242019-08-30T00:00:00.000Z8411143
252019-08-30T00:00:00.000Z858339
262019-09-01T00:00:00.000Z822434
272019-09-01T00:00:00.000Z836535
282019-09-01T00:00:00.000Z8412636
292019-09-01T00:00:00.000Z8513737
302019-09-02T00:00:00.000Z836838
312019-09-02T00:00:00.000Z847953
322019-09-03T00:00:00.000Z81101040
332019-09-03T00:00:00.000Z827953
342019-09-03T00:00:00.000Z837953
352019-09-04T00:00:00.000Z811114
362019-09-04T00:00:00.000Z8211242
372019-09-04T00:00:00.000Z8331343
382019-09-04T00:00:00.000Z848242
392019-09-04T00:00:00.000Z8511143
402019-09-05T00:00:00.000Z8211143
MySQL
SELECT Timepair.id 'timepair.id', start_pair, end_pair,
    Schedule.id 'schedule.id', date, class, number_pair, teacher, subject, classroom
FROM Timepair
    LEFT JOIN Schedule ON Schedule.number_pair = Timepair.id;
timepair.idstart_pairend_pairschedule.iddateclassnumber_pairteachersubjectclassroom
108:30:0009:15:00352019-09-04T00:00:00.000Z811114
108:30:0009:15:00322019-09-03T00:00:00.000Z81101040
108:30:0009:15:00212019-08-30T00:00:00.000Z817953
108:30:0009:15:00162019-08-30T00:00:00.000Z912434
108:30:0009:15:00132019-09-05T00:00:00.000Z9131343
108:30:0009:15:00102019-09-04T00:00:00.000Z919939
108:30:0009:15:0072019-09-03T00:00:00.000Z915636
108:30:0009:15:0042019-09-02T00:00:00.000Z914313
108:30:0009:15:0012019-09-01T00:00:00.000Z9111147
209:20:0010:05:00402019-09-05T00:00:00.000Z8211143
209:20:0010:05:00362019-09-04T00:00:00.000Z8211242
209:20:0010:05:00332019-09-03T00:00:00.000Z827953
209:20:0010:05:00262019-09-01T00:00:00.000Z822434
209:20:0010:05:00222019-08-30T00:00:00.000Z827953
209:20:0010:05:00172019-08-30T00:00:00.000Z928213
209:20:0010:05:00142019-09-05T00:00:00.000Z9211147
209:20:0010:05:00112019-09-04T00:00:00.000Z92101040
209:20:0010:05:0082019-09-03T00:00:00.000Z9213737
209:20:0010:05:0052019-09-02T00:00:00.000Z922434
209:20:0010:05:0022019-09-01T00:00:00.000Z928213
310:15:0011:00:00372019-09-04T00:00:00.000Z8331343
310:15:0011:00:00342019-09-03T00:00:00.000Z837953
310:15:0011:00:00302019-09-02T00:00:00.000Z836838
310:15:0011:00:00272019-09-01T00:00:00.000Z836535
310:15:0011:00:00232019-08-30T00:00:00.000Z838238
310:15:0011:00:00182019-08-30T00:00:00.000Z936535
310:15:0011:00:00152019-09-05T00:00:00.000Z935636
310:15:0011:00:00122019-09-04T00:00:00.000Z9331141
310:15:0011:00:0092019-09-03T00:00:00.000Z936838
310:15:0011:00:0062019-09-02T00:00:00.000Z936535
310:15:0011:00:0032019-09-01T00:00:00.000Z934313
411:05:0011:50:00382019-09-04T00:00:00.000Z848242
411:05:0011:50:00312019-09-02T00:00:00.000Z847953
411:05:0011:50:00282019-09-01T00:00:00.000Z8412636
411:05:0011:50:00242019-08-30T00:00:00.000Z8411143
411:05:0011:50:00202019-09-03T00:00:00.000Z94101040
411:05:0011:50:00192019-08-30T00:00:00.000Z9410147
512:50:0013:35:00392019-09-04T00:00:00.000Z8511143
512:50:0013:35:00292019-09-01T00:00:00.000Z8513737
512:50:0013:35:00252019-08-30T00:00:00.000Z858339
613:40:0014:25:00<NULL><NULL><NULL><NULL><NULL><NULL><NULL>
714:35:0015:20:00<NULL><NULL><NULL><NULL><NULL><NULL><NULL>
815:25:0016:10:00<NULL><NULL><NULL><NULL><NULL><NULL><NULL>

В выборку попали все строки из левой таблицы, дополненные данными о занятиях. Примечательно, что в конце таблицы есть строки с полями, заполненными NULL. Это те строки, для которых не нашлось соответствующих занятий, однако они присутствуют в левой таблице, поэтому тоже были выведены.

Внешнее правое соединение (RIGHT OUTER JOIN)

Соединение, которое возвращает все значения из правой таблицы, соединённые с соответствующими значениями из левой таблицы, если они удовлетворяют условию соединения, или заменяет их на NULL в обратном случае.

Внешнее полное соединение (FULL OUTER JOIN)

Соединение, которое выполняет внутреннее соединение записей и дополняет их левым внешним соединением и правым внешним соединением.

Алгоритм работы полного соединения:

  • Формируется таблица на основе внутреннего соединения (INNER JOIN)
  • В таблицу добавляются значения, не вошедшие в результат формирования из левой таблицы (LEFT OUTER JOIN)
  • В таблицу добавляются значения, не вошедшие в результат формирования из правой таблицы (RIGHT OUTER JOIN)

Соединение FULL JOIN реализовано не во всех СУБД. Например, в MySQL оно отсутствует, однако его можно очень просто эмулировать:

MySQL
SELECT *
FROM левая_таблица
LEFT JOIN правая_таблица
   ON правая_таблица.ключ = левая_таблица.ключ

UNION ALL

SELECT *
FROM левая_таблица
RIGHT JOIN правая_таблица
ON правая_таблица.ключ = левая_таблица.ключ
 WHERE левая_таблица.ключ IS NULL

Базовые запросы для разных вариантов объединения таблиц

СхемаЗапрос с JOIN

Получение всех данных из левой таблицы, соединённых с соответствующими данными из правой:

MySQL
SELECT поля_таблиц 
FROM левая_таблица LEFT JOIN правая_таблица 
    ON правая_таблица.ключ = левая_таблица.ключ 

Получение всех данных из правой таблицы, соединённых с соответствующими данными из левой:

MySQL
SELECT поля_таблиц
FROM левая_таблица RIGHT JOIN правая_таблица
    ON правая_таблица.ключ = левая_таблица.ключ

Получение данных, относящихся только к левой таблице:

MySQL
SELECT поля_таблиц
FROM левая_таблица LEFT JOIN правая_таблица
    ON правая_таблица.ключ = левая_таблица.ключ
WHERE правая_таблица.ключ IS NULL

Получение данных, относящихся только к правой таблице:

MySQL
SELECT поля_таблиц
FROM левая_таблица RIGHT JOIN правая_таблица
    ON правая_таблица.ключ = левая_таблица.ключ
WHERE левая_таблица.ключ IS NULL

Получение данных, относящихся как к левой, так и к правой таблице:

MySQL
SELECT поля_таблиц
FROM левая_таблица INNER JOIN правая_таблица
    ON правая_таблица.ключ = левая_таблица.ключ

Получение всех данных, относящихся к левой и правой таблицам, а также их внутреннему соединению:

MySQL
SELECT поля_таблиц 
FROM левая_таблица
    FULL OUTER JOIN правая_таблица
    ON правая_таблица.ключ = левая_таблица.ключ

Получение данных, не относящихся к левой и правой таблицам одновременно (обратное INNER JOIN):

MySQL
SELECT поля_таблиц 
FROM левая_таблица
    FULL OUTER JOIN правая_таблица
    ON правая_таблица.ключ = левая_таблица.ключ
WHERE левая_таблица.ключ IS NULL
    OR правая_таблица.ключ IS NULL