Какие знаешь типы соединения таблиц SQL?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Типы соединения таблиц (JOIN) в SQL
Основной синтаксис
SELECT columns
FROM table1
JOIN table2 ON table1.id = table2.table1_id;
1. INNER JOIN (внутреннее соединение)
Что возвращает: только совпадающие строки из обеих таблиц
Синтаксис:
SELECT q.title, a.text, u.name
FROM Question q
INNER JOIN Answer a ON q.id = a.question_id
INNER JOIN User u ON a.user_id = u.id;
Диаграмма:
Question Answer
┌────┐ ┌────┐
│ Q1 │ ──→ │ A1 │ (совпадение)
│ Q2 │ ──→ │ A2 │ (совпадение)
│ Q3 │ X │ │ (Q3 без ответов - не будет в результате)
└────┘ └────┘
Результат: Q1-A1, Q2-A2 (только пересечение)
Визуально (диаграмма Венна):
table1 table2
┌────────────┐
│ MATCH │
│ (INNER) │
└────────────┘
Пример результата:
title | text | name
───────────────────────┼──────────────────┼───────
System Design | Use load balancer | John
Database Optimization | Index your data | Jane
Когда использовать:
- Нужны данные ТОЛЬКО если есть соответствие
- Самый частый JOIN
- Забыть что-то - нечего, всё есть
2. LEFT JOIN (левое внешнее соединение)
Что возвращает: ВСЕ строки из левой таблицы + совпадающие из правой (NULL если нет совпадения)
Синтаксис:
SELECT q.title, a.text, u.name
FROM Question q
LEFT JOIN Answer a ON q.id = a.question_id
LEFT JOIN User u ON a.user_id = u.id;
Диаграмма:
Question Answer
┌────┐ ┌────┐
│ Q1 │ ──→ │ A1 │ (совпадение)
│ Q2 │ ──→ │ A2 │ (совпадение)
│ Q3 │ X │ NULL │ (Q3 без ответов - будет NULL)
└────┘ └────┘
Результат: Q1-A1, Q2-A2, Q3-NULL (всё из левой!)
Визуально (диаграмма Венна):
table1 table2
┌─────┬────────┐
│LEFT │ MATCH │
│ + │ │
└─────┴────────┘
Пример результата:
title | text | name
───────────────────────┼──────────────────┼───────
System Design | Use load balancer | John
Database Optimization | Index your data | Jane
Network Protocols | NULL | NULL
Когда использовать:
- Нужны все вопросы, даже без ответов
- Поиск "несвязанных" данных (NULL в правой таблице = нет ответов)
- Проверка целостности данных
3. RIGHT JOIN (правое внешнее соединение)
Что возвращает: ВСЕ строки из правой таблицы + совпадающие из левой (NULL если нет совпадения)
Синтаксис:
SELECT q.title, a.text
FROM Question q
RIGHT JOIN Answer a ON q.id = a.question_id;
Визуально (диаграмма Венна):
table1 table2
┌────────┬────────┐
│ MATCH │ RIGHT │
│ │ + │
└────────┴────────┘
Пример результата:
title | text
───────────────────────┼──────────────────
System Design | Use load balancer
Database Optimization | Index your data
NULL | Try caching
Когда использовать:
- Редко в продакшене
- Можно переписать как LEFT JOIN с перевёрнутыми таблицами
Переписать RIGHT на LEFT:
-- Вместо этого (RIGHT JOIN):
SELECT q.title, a.text
FROM Question q
RIGHT JOIN Answer a ON q.id = a.question_id;
-- Напиши это (LEFT JOIN):
SELECT q.title, a.text
FROM Answer a
LEFT JOIN Question q ON q.id = a.question_id;
4. FULL OUTER JOIN (полное внешнее соединение)
Что возвращает: ВСЕ строки из обеих таблиц (NULL где нет совпадения)
Синтаксис:
SELECT q.title, a.text
FROM Question q
FULL OUTER JOIN Answer a ON q.id = a.question_id;
Визуально (диаграмма Венна):
table1 table2
┌──────┬──────┐
│ LEFT │RIGHT │
│ + │ + │
│ MATCH│ │
└──────┴──────┘
Пример результата:
title | text
───────────────────────┼──────────────────
System Design | Use load balancer
Database Optimization | Index your data
Network Protocols | NULL
NULL | Try caching
Когда использовать:
- Сравнение данных между таблицами
- Поиск "сирот" с обеих сторон
- Проверка согласованности
Важно: не все БД поддерживают FULL OUTER JOIN
- PostgreSQL: ✓ поддерживает
- MySQL: ✗ НЕ поддерживает (эмулировать UNION)
Эмуляция FULL OUTER JOIN в MySQL:
-- PostgreSQL
SELECT * FROM Question
FULL OUTER JOIN Answer ON ...
-- MySQL (эмуляция через UNION)
SELECT * FROM Question
LEFT JOIN Answer ON ...
UNION
SELECT * FROM Answer
LEFT JOIN Question ON ...
WHERE Question.id IS NULL;
5. CROSS JOIN (декартово произведение)
Что возвращает: каждую строку из table1 скрещивает с каждой строкой из table2
Синтаксис:
SELECT p.name, s.name
FROM Profession p
CROSS JOIN Skill s;
Пример:
-- Profession: [System Analyst, Backend Developer]
-- Skill: [SQL, REST API, Caching]
Результат (2 × 3 = 6 строк):
profession | skill
─────────────────────┼──────────────
System Analyst | SQL
System Analyst | REST API
System Analyst | Caching
Backend Developer | SQL
Backend Developer | REST API
Backend Developer | Caching
Когда использовать:
- Генерация всех комбинаций
- Редко в продакшене (может быть дорого!)
- Пример: все комбинации цветов и размеров
6. SELF JOIN (соединение таблицы с самой собой)
Что возвращает: соединение таблицы саму с собой для сравнения строк
Синтаксис:
SELECT
c1.name AS "Child Category",
c2.name AS "Parent Category"
FROM Category c1
LEFT JOIN Category c2 ON c1.parent_id = c2.id;
Пример:
Category (иерархия профессий):
id | name | parent_id
───┼─────────────────────┼──────────
1 | Backend Developer | NULL (root)
2 | Python | 1
3 | Node.js | 1
4 | Web Frameworks | 3
SELF JOIN результат:
child | parent
──────────────┼──────────────
Python | Backend Developer
Node.js | Backend Developer
Web Frameworks| Node.js
Когда использовать:
- Иерархии (категории, сотрудник-менеджер)
- Сравнение похожих записей
- Поиск дубликатов
7. NATURAL JOIN
Что делает: автоматически соединяет по колонкам с одинаковыми названиями
-- Вместо явного ON
SELECT *
FROM Question
NATURAL JOIN Answer;
-- Автоматически соединит по question_id (если это колонка в обеих таблицах)
⚠️ ИЗБЕГАЙ: может привести к неожиданным результатам
- Если добавишь новую колонку с похожим названием → JOIN сломается
- Всегда пиши явно ON или USING
Сравнение всех JOIN'ов
TABLE1: A, B, C
TABLE2: B, C, D
Results
INNER B, C (только совпадение)
LEFT A, B, C (всё из левой)
RIGHT B, C, D (всё из правой)
FULL OUTER A, B, C, D (всё всё всё)
CROSS A×(B,C,D) (все комбинации)
Производительность JOIN'ов
Правила оптимизации
1. Индексы на JOIN колонках
-- Эти колонки должны быть индексированы:
CREATE INDEX idx_answer_question_id ON Answer(question_id);
CREATE INDEX idx_answer_user_id ON Answer(user_id);
2. Избегай функций в JOIN условиях
-- ❌ Медленно (функция препятствует использованию индекса)
FROM Question q
JOIN Answer a ON q.id = a.question_id
WHERE LOWER(q.title) = 'system design';
-- ✓ Быстро
FROM Question q
JOIN Answer a ON q.id = a.question_id
WHERE q.title = 'System Design';
3. Порядок JOIN'ов важен
-- ✓ Хорошо: маленькие таблицы первыми
FROM Question q -- 75k записей
JOIN Answer a ON ... -- 500k записей
JOIN User u ON ... -- 10k записей
-- Оптимайзер переставит, но явно указать - лучше
4. Используй EXPLAIN для анализа
EXPLAIN ANALYZE
SELECT q.title, COUNT(a.id)
FROM Question q
LEFT JOIN Answer a ON q.id = a.question_id
GROUP BY q.id;
Пример для PrepBro
-- Получить все вопросы с количеством ответов
SELECT
q.id,
q.title,
p.name AS profession,
COUNT(a.id) AS answer_count,
AVG(a.score) AS avg_answer_score
FROM Question q
INNER JOIN Profession p ON q.profession_id = p.id
LEFT JOIN Answer a ON q.id = a.question_id
GROUP BY q.id, q.title, p.name
ORDER BY answer_count DESC;
Разбор:
INNER JOIN Profession- только вопросы с профессиейLEFT JOIN Answer- все вопросы, даже без ответовGROUP BY- агрегирование ответов
Итого
7 основных типов JOIN'ов:
| JOIN | Возвращает | Когда |
|---|---|---|
| INNER | Совпадения | Нужны связанные данные |
| LEFT | Всё из левой | Нужны все из левой |
| RIGHT | Всё из правой | Редко (переписать на LEFT) |
| FULL | Всё из обеих | Сравнение, поиск сирот |
| CROSS | Произведение | Генерация комбинаций |
| SELF | Таблица с собой | Иерархии |
| NATURAL | По названиям | Избегай! |
Правила System Analyst: ✓ Всегда определяй тип JOIN в постановке ✓ Убедись, что индексы на FK ✓ Проверь EXPLAIN ANALYZE перед отправкой ✓ Документируй, почему именно этот JOIN ✓ Помни про производительность (LEFT дороже INNER)