CROSS JOIN и SELF JOIN в SQL — что это и когда использовать
Коротко
CROSS JOIN — декартово произведение двух таблиц: каждая строка одной соединяется с каждой строкой другой. SELF JOIN — соединение таблицы с самой собой через алиасы. Оба типа регулярно встречаются на собеседованиях аналитика данных, хотя в повседневных запросах используются реже, чем LEFT или INNER JOIN.
CROSS JOIN — декартово произведение
CROSS JOIN не требует условия ON. Он берёт каждую строку левой таблицы и соединяет с каждой строкой правой. Если в левой таблице M строк, а в правой N — результат содержит M × N строк.
SELECT u.name, p.product_name
FROM users u
CROSS JOIN products p;Если users содержит 3 строки, а products — 4, результат — 12 строк. Каждый пользователь спарен с каждым продуктом.
Альтернативный синтаксис — через запятую без условия:
SELECT u.name, p.product_name
FROM users u, products p;Это тоже CROSS JOIN, просто запись устаревшая. Явный CROSS JOIN читается однозначнее — по нему сразу видно, что декартово произведение задумано, а не получилось случайно.
Когда CROSS JOIN полезен
Генерация date spine
Классика аналитики — построить «каркас» дат, чтобы потом подтянуть метрики через LEFT JOIN. Без CROSS JOIN пришлось бы придумывать обходные пути.
SELECT d.dt, u.user_id
FROM generate_series('2026-01-01'::DATE, '2026-03-31'::DATE, '1 day') AS d(dt)
CROSS JOIN (SELECT DISTINCT user_id FROM events) u;Результат — все комбинации дата × пользователь. Дальше LEFT JOIN с таблицей событий — и у вас полная картина с нулями в днях без активности.
Все пары пользователь × продукт
Для рекомендательных систем или gap-анализа: какие продукты пользователь ещё не покупал?
SELECT u.user_id, p.product_id
FROM users u
CROSS JOIN products p
LEFT JOIN purchases pu
ON pu.user_id = u.user_id AND pu.product_id = p.product_id
WHERE pu.id IS NULL;CROSS JOIN создаёт все возможные пары, LEFT JOIN + IS NULL отсекает уже совершённые покупки.
SELF JOIN — таблица сама с собой
SELF JOIN — это не отдельный тип синтаксиса. Вы используете обычный INNER, LEFT или любой другой JOIN, но обе стороны ссылаются на одну и ту же таблицу с разными алиасами.
SELECT
e.name AS employee,
m.name AS manager
FROM employees e
LEFT JOIN employees m ON e.manager_id = m.id;Здесь employees используется дважды: e — сотрудники, m — их руководители. Алиасы обязательны, иначе SQL не поймёт, к какому экземпляру таблицы относится столбец.
Когда SELF JOIN полезен
Иерархия сотрудник — руководитель
Классический пример выше. На собеседованиях часто просят вывести сотрудников вместе с именем их менеджера — это прямой SELF JOIN.
Поиск пар
Найти всех пользователей из одного города:
SELECT u1.name AS user_1, u2.name AS user_2, u1.city
FROM users u1
JOIN users u2 ON u1.city = u2.city AND u1.user_id < u2.user_id;Условие u1.user_id < u2.user_id исключает дубли (Анна–Борис и Борис–Анна) и пары с самим собой.
Сравнение текущей и предыдущей строки (без оконных функций)
Допустим, нужно посчитать изменение выручки день к дню, а оконные функции использовать нельзя (такое бывает на собеседованиях):
SELECT
t1.dt,
t1.revenue,
t1.revenue - t2.revenue AS revenue_change
FROM daily_stats t1
LEFT JOIN daily_stats t2 ON t2.dt = t1.dt - INTERVAL '1 day';SELF JOIN здесь заменяет LAG(). На практике оконные функции удобнее, но знать оба подхода полезно — на собеседовании могут попросить решить задачу без LAG.
Типичные ошибки
1. Случайный CROSS JOIN из-за забытого ON
-- Вероятно, забыли условие — получили декартово произведение
SELECT u.name, o.order_id
FROM users u
JOIN orders o;Если в users 10 000 строк и в orders 50 000 — результат содержит 500 000 000 строк. База ляжет. Всегда проверяйте, что у каждого JOIN есть условие ON, если это не намеренный CROSS JOIN.
2. CROSS JOIN на больших таблицах
CROSS JOIN 10 000 × 10 000 = 100 000 000 строк. Перед выполнением прикиньте мощность результата: SELECT COUNT(*) FROM a × SELECT COUNT(*) FROM b. Если цифра пугает — подумайте, действительно ли нужны все комбинации.
3. Забытые алиасы в SELF JOIN
Без алиасов SQL не скомпилируется — СУБД не различит два экземпляра одной таблицы. Всегда давайте осмысленные алиасы: e для employee, m для manager, t1/t2 для временных рядов.
Вопросы с собеседований
Что такое CROSS JOIN и когда его использовать?
CROSS JOIN — декартово произведение двух таблиц. Каждая строка одной таблицы соединяется с каждой строкой другой. Используется для генерации всех комбинаций: date spine, все пары пользователь×продукт, матрица регион×категория. В повседневных запросах встречается нечасто, но на собеседовании спрашивают регулярно.
Как написать SELF JOIN? Приведите пример.
SELF JOIN — это JOIN таблицы с самой собой. Синтаксически используется обычный JOIN с двумя алиасами одной таблицы. Пример — вывести сотрудников и их менеджеров: FROM employees e LEFT JOIN employees m ON e.manager_id = m.id.
Чем опасен CROSS JOIN?
Размером результата. M строк × N строк = M×N строк. На маленьких справочниках это безобидно, но на больших таблицах запрос может исчерпать память или работать часами. Всегда оценивайте мощность результата перед запуском.
Можно ли заменить SELF JOIN оконной функцией?
Часто да. Задачи вроде «сравнить текущую строку с предыдущей» решаются через LAG/LEAD без SELF JOIN. Но есть случаи, где SELF JOIN незаменим: поиск пар, иерархии, соединение по произвольному условию. На собеседовании могут попросить решить задачу обоими способами.
Что произойдёт, если написать JOIN без ON?
В большинстве СУБД это эквивалентно CROSS JOIN — декартово произведение. В некоторых (например, PostgreSQL при использовании ключевого слова JOIN) запрос не скомпилируется без ON. В любом случае — отсутствие условия соединения почти всегда ошибка.
FAQ
CROSS JOIN и запятая между таблицами — это одно и то же?
Да. FROM a, b и FROM a CROSS JOIN b дают одинаковый результат — декартово произведение. Но явный CROSS JOIN предпочтительнее: он показывает, что автор запроса намеренно хотел все комбинации, а не забыл условие WHERE.
Можно ли использовать WHERE с CROSS JOIN?
Да. CROSS JOIN + WHERE эквивалентен INNER JOIN с условием в ON. Но это устаревший стиль — лучше сразу писать INNER JOIN с ON, так читабельнее.
В каких СУБД работают CROSS JOIN и SELF JOIN?
Во всех основных: PostgreSQL, MySQL, SQL Server, Oracle, BigQuery, ClickHouse, Redshift. Синтаксис стандартный, различий между СУБД практически нет.
Подробнее о всех типах JOIN — в шпаргалке по JOIN. Разницу между LEFT и INNER JOIN разбираем здесь. Больше примеров вопросов — в каталоге.
Чтобы закрепить CROSS JOIN и SELF JOIN на практике — откройте тренажёр. 10 минут в день в Telegram, и на собеседовании эти темы не вызовут затруднений. Подробности о формате — на странице SQL-тренажёра.