Пары пользователей, купивших один товар
// Условие
Найдите пары пользователей, которые купили один и тот же товар (в завершённых заказах). Выведите product_id, user_id_1 (меньший) и user_id_2 (больший). Уберите дубли пар. Ограничьте результат первыми 20 строками, отсортированными по product_id, затем по user_id_1, затем по user_id_2.
// Таблицы
sandbox.orders
order_id | INT |
user_id | INT |
order_date | TIMESTAMP |
amount | NUMERIC(10,2) |
status | VARCHAR(20) |
delivery_days | INT |
promo_code | VARCHAR(20) |
sandbox.order_items
item_id | INT |
order_id | INT |
product_id | INT |
quantity | INT |
unit_price | NUMERIC(10,2) |
// Что тренирует
SELF JOINCTEDISTINCT
// Решение
Подсказка
SELF JOIN: таблицу «пользователь-товар» соединяем саму с собой по product_id. Условие a.user_id < b.user_id убирает дубли и пару с самим собой.
Сначала попробуй сам → Показать решение
WITH user_products AS (
SELECT DISTINCT
o.user_id,
oi.product_id
FROM sandbox.orders o
JOIN sandbox.order_items oi ON o.order_id = oi.order_id
WHERE o.status = 'completed'
)
SELECT
a.product_id,
a.user_id AS user_id_1,
b.user_id AS user_id_2
FROM user_products a
JOIN user_products b
ON a.product_id = b.product_id
AND a.user_id < b.user_id
ORDER BY a.product_id, a.user_id, b.user_id
LIMIT 20;
SELF JOIN — мощный паттерн. Трюк a.user_id < b.user_id решает сразу две проблемы: (1) убирает пару пользователя с самим собой (=), (2) убирает дубли — пара (1, 5) и (5, 1) превращается в одну (1, 5). CTE с DISTINCT убирает дублирование, если пользователь купил товар в нескольких заказах.