Как соединить таблицу саму с собой в SQL (self join)?
В таблице сотрудников есть поле manager_id, которое ссылается на id другого сотрудника в этой же таблице. Как вывести имя сотрудника рядом с именем его руководителя? Как соединить таблицу саму с собой?
2 ответа
Когда строка ссылается на другую строку той же таблицы, делают self join — соединение таблицы с самой собой. Секрет в том, что таблицу нужно подключить дважды под разными алиасами, как будто это две разные таблицы:
SELECT
e.name AS employee,
m.name AS manager
FROM employees AS e
LEFT JOIN employees AS m
ON e.manager_id = m.id;
Здесь e — это «сотрудник», а m — «его руководитель», хотя физически это одна таблица employees. Условие e.manager_id = m.id связывает сотрудника с тем, кто им руководит.
Почему LEFT JOIN, а не INNER: у самого верхнего начальника manager_id обычно NULL (у него нет руководителя). INNER JOIN выкинул бы его из результата, а LEFT JOIN оставит, подставив в колонку manager значение NULL. Если хотите, можно показать это явно:
SELECT e.name AS employee,
COALESCE(m.name, 'нет руководителя') AS manager
FROM employees AS e
LEFT JOIN employees AS m ON e.manager_id = m.id;
Главное правило self join — обязательные разные алиасы. Без них (FROM employees JOIN employees ON ...) СУБД не поймёт, к какому из двух экземпляров относится столбец id или name, и выдаст ошибку неоднозначности.
Такой приём используют не только для иерархий «сотрудник-начальник», но и чтобы, например, найти пары строк с одинаковым значением какого-то поля.
Аналогия, чтобы уложилось: представьте, что вы взяли две копии одного и того же списка сотрудников и положили рядом. В левой копии (e) ищете человека, в правой (m) — по его manager_id находите начальника. Физически таблица одна, но алиасы e и m заставляют SQL обращаться с ней как с двумя. Для глубоких иерархий (начальник начальника и так далее) одного self join мало — там нужны рекурсивные запросы WITH RECURSIVE.