JOIN и операции множеств: вопросы для собеседования (часть 2)

JOIN-ы — фундамент аналитического SQL. INNER, LEFT, RIGHT, FULL OUTER, CROSS JOIN, а также UNION, INTERSECT, EXCEPT — на собеседовании нужно не просто знать синтаксис, но и понимать, что происходит при дубликатах ключей и NULL-значениях. Задачи на JOIN встречаются на каждом собеседовании без исключения.

Агрегация, GROUP BY и HAVINGДаты и времяEXPLAIN и оптимизацияВыражения и NULLОсновы SQL-запросовСтроки и приведение типовПодзапросы и CTEОконные функции

Вопросы 610 из 40

6Нужно получить уникальный список `user_id`, которые пришли из двух каналов: `campaign_a(user_id)` и `campaign_b(user_id)`. Как корректнее объединить списки, чтобы убрать дубликаты?
AИспользовать `UNION`
BИспользовать `UNION ALL`
CИспользовать `INNER JOIN` по `user_id`
DИспользовать `FULL JOIN` по `user_id`
Ответ: `UNION` возвращает множество (без дублей), а `UNION ALL` просто добавляет строки и сохраняет дубликаты.

Если один и тот же `user_id` есть в обеих таблицах, `UNION` вернёт его один раз. `UNION ALL` вернёт две строки (и дальше может раздуть метрики, если вы просто посчитаете строки). `JOIN` решает другую задачу — соединение данных по ключу.

7Есть две таблицы с одинаковой схемой: `events_web(user_id, event_name, created_at)` и `events_app(user_id, event_name, created_at)`. Нужно получить общий поток событий для дальнейшей агрегации. Что использовать?
A`INNER JOIN` по `user_id`
B`LEFT JOIN` по `user_id`
C`FULL JOIN` по `user_id`
D`UNION ALL` между двумя выборками
Ответ: `UNION ALL` «складывает» строки из двух источников вертикально; `JOIN` соединяет колонки горизонтально по ключу.

Когда нужно объединить записи одинакового формата из разных источников (web и app), применяют операции над наборами: `UNION`/`UNION ALL`. `JOIN` используется для добавления атрибутов по ключу и не предназначен для «склейки» двух логов событий в один поток. Обычно берут `UNION ALL`, чтобы не терять повторяющиеся события и не тратить время на удаление дублей.

8Нужно вывести пользователей, у которых есть хотя бы один заказ. У каждого пользователя может быть много заказов. Какой способ не создаст дублирование строк?
AНаписать `WHERE EXISTS (SELECT 1 FROM orders o WHERE o.user_id = u.id)` — остановится на первом совпадении
BНаписать `INNER JOIN orders o ON o.user_id = u.id` — вернёт ровно по одной строке на пользователя
CНаписать `WHERE u.id IN (SELECT DISTINCT user_id FROM orders)` — `DISTINCT` ускоряет поиск по индексу
DНаписать `INNER JOIN (SELECT user_id FROM orders LIMIT 1) o ON o.user_id = u.id` — ограничит результат
Ответ: `EXISTS` проверяет наличие хотя бы одной строки и не дублирует результат, тогда как `INNER JOIN` создаст по строке на каждый заказ.

`EXISTS (подзапрос)` — это полусоединение (semi-join): для каждого пользователя проверяется, существует ли хотя бы одна строка в `orders`, и поиск прекращается при первом совпадении. Результат — ровно одна строка на пользователя. `INNER JOIN` без предварительной дедупликации `orders` создаст столько строк, сколько заказов у пользователя. `IN` тоже работает корректно, но `DISTINCT` внутри не «быстрее индекса».

9В таблицах `orders` и `users` есть одноимённые столбцы: `user_id`, `updated_at`, `status`. Аналитик пишет `SELECT * FROM orders NATURAL JOIN users`. Что произойдёт?
AСоединение произойдёт только по `user_id`, как задумано аналитиком при написании запроса
BЗапрос вернёт ошибку, потому что `NATURAL JOIN` не поддерживается в PostgreSQL на таблицах
CСоединение произойдёт по столбцу `id` из обеих таблиц — `NATURAL JOIN` берёт первый столбец
DСоединение произойдёт по всем одноимённым столбцам: `user_id`, `updated_at` и `status`
Ответ: `NATURAL JOIN` автоматически соединяет по всем столбцам с одинаковыми именами — здесь по `user_id`, `updated_at` и `status`, что почти наверняка не то, что нужно.

`NATURAL JOIN` находит все пары одноимённых столбцов и использует их как условие `ON`. Если помимо `user_id` совпадают `updated_at` и `status`, соединение потребует совпадения всех трёх — это резко сократит результат или вернёт пустую таблицу. Добавление нового столбца с тем же именем в любую таблицу молча сломает запрос. Поэтому `NATURAL JOIN` считается опасным в продакшне.

10Вы объединяете логи событий из двух источников `events_web` и `events_app`, чтобы посчитать количество событий. Важно не потерять повторяющиеся события (например, два одинаковых клика). Что лучше использовать для объединения?
A`UNION`, потому что он ускоряет подсчёт событий
B`INTERSECT`, потому что он берёт общие события
C`EXCEPT`, чтобы исключить дубликаты
D`UNION ALL`, чтобы сохранить все строки
Ответ: `UNION ALL` сохраняет все строки, а `UNION` удаляет дублирующиеся строки и может занизить количество событий.

В событийных логах одинаковые строки могут быть валидными повторениями (два клика, две покупки и т.д.). Если использовать `UNION`, одинаковые строки будут схлопнуты, и метрика количества событий станет неверной. Поэтому для подсчётов по логам обычно применяют `UNION ALL`.

12345678

Хотите тренировать интерактивно?

В приложении — таймер, прогресс, стрики и 1700+ вопросов по всем темам.

Тренировать в Telegram

Другие темы: SQL

Агрегация, GROUP BY и HAVINGДаты и времяEXPLAIN и оптимизацияВыражения и NULLОсновы SQL-запросовСтроки и приведение типовПодзапросы и CTEОконные функции