Условие
Какой запрос вернёт все уникальные комбинации записей из двух таблиц table1 и table2?
Решение
SELECT DISTINCT *
FROM table1
CROSS JOIN table2;CROSS JOIN — это декартово произведение: каждая строка из table1 соединяется с каждой строкой из table2. Если в первой таблице n строк, во второй m — на выходе будет n × m строк.
DISTINCT уберёт идентичные комбинации (если они возникнут от дубликатов в исходных таблицах).
Альтернативные синтаксисы
-- ANSI
SELECT * FROM a CROSS JOIN b;
-- через FROM с запятой (старый стиль)
SELECT * FROM a, b;
-- через JOIN без условия
SELECT * FROM a JOIN b ON 1 = 1;Все три эквивалентны.
Где применяется на практике
| Сценарий | Пример |
|---|---|
| Generation: все пары | Тестирование размерностей (city × month) для отчёта |
| Заполнение пробелов | dates × users для построения временного ряда без пропусков |
| Расчёт всех vs всех | Подобие или совместная вероятность |
Заполнение пробелов в отчёте
-- цель: показать каждый день каждого пользователя, даже если активности не было
SELECT u.user_id, d.dt, COALESCE(a.events, 0) AS events
FROM users u
CROSS JOIN generate_series('2024-01-01'::date, '2024-01-31', '1 day') AS d(dt)
LEFT JOIN activity a ON a.user_id = u.user_id AND a.dt = d.dt;Подводные камни
- Случайный CROSS JOIN — частая ошибка: забыли условие в
JOIN ... ON, и получили миллионы строк вместо тысяч. - DISTINCT дорог — на больших объёмах сортирует и хеширует; если знаете, что дублей нет, не пишите DISTINCT.
SELECT *после CROSS JOIN — все колонки обеих таблиц. Если есть колонки с одинаковыми именами, при выборе по алиасу возможна путаница.- Размер результата —
1000 × 1000 = 1Mстрок. Перед запуском прикиньтеn × m, иначе порвёте память.
Эталонный ответ
SELECT DISTINCT *
FROM table1
CROSS JOIN table2;CROSS JOIN даёт декартово произведение n × m; DISTINCT уберёт дубликаты, если они есть.