Какие типы JOIN существуют в SQL и чем они отличаются?

Ответ

JOIN — это операция SQL для объединения строк из двух или более таблиц на основе логической связи между ними.

Основные типы JOIN (на примере таблиц employees и departments):

Тип JOIN Описание Визуализация (Венна)
INNER JOIN Возвращает только строки, где есть совпадение в обеих таблицах. Пересечение множеств.
LEFT (OUTER) JOIN Возвращает все строки из левой таблицы и совпадающие строки из правой. Если совпадения нет, поля правой таблицы будут NULL. Все левое множество + пересечение.
RIGHT (OUTER) JOIN Возвращает все строки из правой таблицы и совпадающие строки из левой. Аналог LEFT JOIN с поменянными таблицами. Все правое множество + пересечение.
FULL (OUTER) JOIN Возвращает строки при наличии совпадения в любой из таблиц. Объединение LEFT и RIGHT JOIN. Полное объединение множеств.
CROSS JOIN Возвращает декартово произведение строк — каждая строка первой таблицы соединяется с каждой строкой второй. Все со всеми.

Примеры запросов:

-- INNER JOIN: Сотрудники с известным отделом
SELECT e.name, d.department_name
FROM employees e
INNER JOIN departments d ON e.department_id = d.id;

-- LEFT JOIN: Все сотрудники, даже без отдела
SELECT e.name, d.department_name
FROM employees e
LEFT JOIN departments d ON e.department_id = d.id;

-- FULL JOIN: Все сотрудники и все отделы
SELECT e.name, d.department_name
FROM employees e
FULL OUTER JOIN departments d ON e.department_id = d.id;

-- CROSS JOIN: Все возможные комбинации (редко используется напрямую)
SELECT e.name, d.department_name
FROM employees e
CROSS JOIN departments d;

В контексте Java и JPA:

  • JDBC: JOIN выполняется на уровне SQL-запроса, передаваемого через Statement или PreparedStatement.
  • JPA/Hibernate: JOIN часто реализуется неявно через навигацию по связям между сущностями (аннотации @ManyToOne, @OneToMany). Явный JOIN можно написать в JPQL:
    // JPQL пример
    String jpql = "SELECT e FROM Employee e JOIN e.department d WHERE d.name = :deptName";

Ответ 18+ 🔞

Давайте разберём этот ваш JOIN, а то некоторые думают, что это такой новый вид йоги или марка джинсов. Нет, блядь, это просто способ склеить таблицы в базе данных, чтобы не бегать туда-сюда, как угорелый.

Представьте, у вас есть таблица employees — это ваши работнички, и таблица departments — отделы, где они якобы трудятся. А связывает их какой-нибудь department_id. Вот JOIN — это и есть процесс их сведения, чтобы понять, кто где сидит и, главное, кто вообще нигде не сидит и просто деньги получает.

Основные виды склейки, или "давай поженим эти таблицы":

Тип JOIN Что делает (человеческим языком) На что похоже
INNER JOIN Возвращает только тех, у кого есть пара. Сотрудник с отделом, отдел с сотрудником. Одиночек и пустые отделы — нахуй, в результат не попали. Как встреча выпускников: пришли только те, у кого и имя в списке есть, и сам человек явился.
LEFT JOIN Все сотрудники из левой таблицы — важны! А отдел — если найдётся. Не нашёлся отдел у Васька-стажёра? Ну и хуй с ним, пишем NULL. Главное — список сотрудников полный. Как построение на плацу: весь личный состав (слева) есть, а напротив каждого пишем его взвод (справа). Кого не распределили — так и пишем "без взвода".
RIGHT JOIN То же самое, но наоборот. Все отделы важны! А сотрудники в них — если есть. Нет людей в отделе "Потерянные души"? Отдел всё равно в отчёте будет, просто с NULL вместо фамилий. По сути, это LEFT JOIN, но таблицы местами поменяли.
FULL JOIN А вот это уже полный пиздец, простите, объединение. Берём ВСЕХ сотрудников и ВСЕ отделы. Кто с кем сошёлся — молодцы. Кто одинок — тоже в списке, но с пустыми полями рядом. Полная картина бардака. Общая ведомость: и все люди, и все комнаты в офисе. Сопоставляем, кто в какой комнате. Свободные комнаты и бесхозные люди — тоже в списке.
CROSS JOIN А это, блядь, самое весёлое. Декартово произведение, ёпта. Каждого сотрудника женим на каждом отделе. Получаем все возможные пары. Если 100 сотрудников и 10 отделов, будет 1000 строк. Овердохуища комбинаций. Используется редко, иначе сервер взвоет, как сука. Как если бы вы взяли список всех мужчин и всех женщин в городе и составили абсолютно все возможные пары для свидания. Абсурд, но иногда нужно.

Как это выглядит в коде, эти ваши запросы:

-- INNER JOIN: Дайте мне только адекватных, у кого всё по полочкам
SELECT e.name, d.department_name
FROM employees e
INNER JOIN departments d ON e.department_id = d.id;

-- LEFT JOIN: Дайте мне всех работяг, а там видно будет, есть ли у них контора
SELECT e.name, d.department_name
FROM employees e
LEFT JOIN departments d ON e.department_id = d.id;

-- FULL JOIN: Хочу увидеть ВСЁ, всю подноготную! И сирот, и пустые кабинеты!
SELECT e.name, d.department_name
FROM employees e
FULL OUTER JOIN departments d ON e.department_id = d.id;

-- CROSS JOIN: (делает глубокий вдох) А давайте переберём все варианты, мать его!
SELECT e.name, d.department_name
FROM employees e
CROSS JOIN departments d;

А при чём тут Java, спросите вы? Ну, при всём, ядрёна вошь!

  • Чистый JDBC: Ты просто пишешь этот SQL-текст, как есть, в PreparedStatement и запускаешь. База данных всё сделает, тебе только результат разобрать.
  • JPA/Hibernate (этот ваш хайбернейт): Тут уже можно не париться с JOIN вручную, если связи между сущностями (@ManyToOne и прочая хуйня) настроены. Объекты сами подтянутся. Но если очень хочется поконтролировать, пишем JPQL:

    // Типичный запрос на ORM-сленге
    String jpql = "SELECT e FROM Employee e JOIN e.department d WHERE d.name = :deptName";

    Перевод: "Дай мне всех сотрудников (e), которые приджойнены к своему отделу (d), но только если отдел называется, например, 'Бухгалтерия'". И не надо самому писать ON e.id = d.id, фреймворк уже всё проеб... то есть, предусмотрел.

Вот и вся магия. Главное — понять, что тебе нужно: только пары, все левые, все правые или вообще все подряд. А то CROSS JOIN на больших таблицах — это верный способ отправить базу в глубокий и долгий запой.