JavaRush /Курсы /SQL SELF /Самообъединение данных с помощью SELF JOIN

Самообъединение данных с помощью SELF JOIN

SQL SELF
12 уровень , 3 лекция
Открыта

SELF JOIN — это способ объединения таблицы самой с собой. Это может показаться странным на первый взгляд: зачем объединять таблицу саму с собой? Но в реальной жизни такие задачи встречаются довольно часто. Например, представьте, что у вас есть таблица сотрудников, и каждый сотрудник имеет менеджера. Менеджер сам тоже является сотрудником, а значит, его данные находятся в той же таблице. SELF JOIN поможет нам сопоставить сотрудников с их менеджерами.

Если говорить формально, SELF JOIN — это обычный JOIN, но в нем мы используем одну и ту же таблицу дважды, присваивая ей разные псевдонимы (или алиасы), чтобы отличить её "версии".

SELF JOIN можно использовать для:

  • Иерархических связей: установление отношений "родитель-дочерний элемент", например, сотрудник и его менеджер.
  • Анализа данных внутри таблицы: сравнение записей в таблице, например, поиск похожих товаров или событий.
  • Сложных запросов к структурам с дублирующейся логикой.

Синтаксис SELF JOIN

Давайте для большей ясности сразу посмотрим на упрощённый синтаксис SELF JOIN:

SELECT
    A.column_name,
    B.column_name
FROM 
    table_name A
JOIN 
    table_name B
ON 
    A.common_column = B.common_column;

Здесь:

  • table_name A и table_name B — это одна и та же таблица, но с разными псевдонимами.
  • A.common_column и B.common_column — столбцы, которые используются для объединения записей.

Псевдонимы (A и B) нужны для того, чтобы СУБД "понимала", с какой из "копий" таблицы вы работаете.

Примеры использования SELF JOIN

Пример 1: список сотрудников и их менеджеров

Итак, предположим, у нас есть таблица employees, которая выглядит следующим образом:

employee_id name manager_id
1 Alex Lin NULL
2 Maria Chi 1
3 Otto Song 1
4 Nina Zhao 2

В этой таблице:

  • employee_id — идентификатор сотрудника.
  • name — имя сотрудника.
  • manager_id — идентификатор менеджера, который также является employee_id другого сотрудника.

Задача: получить список сотрудников и их менеджеров.

Вот так эта задача решается с помощью SELF JOIN:

SELECT
    e.name AS employee_name,
    m.name AS manager_name
FROM 
    employees e
LEFT JOIN 
    employees m
ON 
    e.manager_id = m.employee_id;

Результат:

employee_name manager_name
Alex Lin NULL
Maria Chi Alex Lin
Otto Song Alex Lin
Nina Zhao Maria Chi

Здесь:

  • Таблица e — это "сотрудники".
  • Таблица m — это тоже "сотрудники", но в роли "менеджеров".

У Alex Lin нет менеджера manager_id = NULL, поэтому в результате поле manager_name будет пустым.

Пример 2: Поиск похожих товаров

Допустим, у нас есть таблица products:

product_id product_name category
1 Холодильник Техника
2 Стиральная машина Техника
3 Смартфон Гаджеты
4 Планшет Гаджеты

Задача: найти пары товаров, которые принадлежат одной категории.

Решение с использованием SELF JOIN:

SELECT
    p1.product_name AS product_1,
    p2.product_name AS product_2
FROM 
    products p1
JOIN 
    products p2
ON 
    p1.category = p2.category
AND 
    p1.product_id < p2.product_id;

Результат:

product_1 product_2
Холодильник Стиральная машина
Смартфон Планшет

Обратите внимание на условие p1.product_id < p2.product_id. Оно позволяет избежать дублирования пар, например, чтобы в результатах не появлялись строки типа Холодильник — Стиральная машина и Стиральная машина — Холодильник.

Пример 3: Анализ иерархий (родители и потомки)

Рассмотрим еще один пример. Допустим, у нас есть таблица categories:

category_id category_name parent_id
1 Техника NULL
2 Гаджеты 1
3 Компьютеры 1
4 Смартфоны 2

Здесь:

  • category_id — идентификатор категории.
  • category_name — название категории.
  • parent_id — идентификатор родительской категории.

Задача: сопоставить категории и их родительские категории.

Запрос:

SELECT
    c1.category_name AS child_category,
    c2.category_name AS parent_category
FROM 
    categories c1
LEFT JOIN 
    categories c2
ON 
    c1.parent_id = c2.category_id;

Результат:

child_category parent_category
Техника NULL
Гаджеты Техника
Компьютеры Техника
Смартфоны Гаджеты

Типичные ошибки при использовании SELF JOIN

Забыли указать алиасы (псевдонимы): если не использовать алиасы, становится невозможно отличить одну "копию" таблицы от другой.

Циклические ссылки: если данные содержат циклические ссылки (например, сотрудник сам себе менеджер), это может привести к неожиданным результатам.

Дублирование результатов: не забывайте фильтровать результаты (например, с помощью p1.product_id < p2.product_id), чтобы избежать дублирования.

SELF JOIN — это мощный инструмент при работе с данными, и его правильное использование позволяет решать сложные задачи с иерархиями, связями внутри таблиц и анализом данных. Надеюсь, теперь вы видите, насколько полезен этот "селфи" во вселенной SQL!

2
Задача
SQL SELF, 12 уровень, 3 лекция
Недоступна
Самообъединение для поиска менеджеров сотрудников
Самообъединение для поиска менеджеров сотрудников
2
Задача
SQL SELF, 12 уровень, 3 лекция
Недоступна
Самообъединение для поиска связанных товаров
Самообъединение для поиска связанных товаров
Комментарии (8)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
Anemon Уровень 13 Expert
12 сентября 2025
🤓
Denis Murashko Уровень 27
26 августа 2025
Первую задачу так и не исправили
Vlad Tagunkov Уровень 37
27 декабря 2025
все еще не поправили
Elena Уровень 30
9 июля 2025
Как так та? Первая задача. "Запрос должен использовать `SELF JOIN`" в ошибке указано "Используйте 'LEFT JOIN' вместо 'SELF JOIN' для корректного объединения таблицы с самой собой.". Вы бы определились для начала!
Dmitry Ivanchenko Уровень 15
14 января 2026
"SELF" это не ключевое слово, а название принципа джойна таблицы с собой. Тупая нейронка не может понять что это надо объяснить. Тупой курс
25 июня 2025
Для инициализации 17 задачи возможно придется добавить CASCADE, хотя это следовало бы сделать во всех задачах

DROP TABLE IF EXISTS employees CASCADE;
Юрий Уровень 60
27 июня 2025
Благо среда подсказывает
Сергей Третяк Уровень 14
28 октября 2025
Да уж, без CASCADE в DROP TABLE задача не работает, видимо связи со старыми init.sql мешают.