Используйте DISTINCT по user_id и SKU, а покупки фильтруйте относительно первого бана. Однофамильцев нельзя объединять только по имени.
Отбор уникальных пар пользователь‑товар до даты бана
Используйте DISTINCT по user_id и SKU, а покупки фильтруйте относительно первого бана. Однофамильцев нельзя объединять только по имени.
Короткий ответ
Что ответить на собеседовании
Подробный разбор
Ответ с пояснениями
Условие
Нужно получить набор уникальных сочетаний пользователя и идентификатора товара (SKU) для всех покупок, совершённых до того момента, как пользователь оказался в списке забаненных. Результат следует упорядочить сначала по имени пользователя, а затем по коду товара.
//user
id|firstname|lastname |birth
1 | Ivan | Petrov | 1996-05-01
2 | Anna | Petrova | 1996-06-01
3 | Ivan | Petrov | 1996-10-02
// purchase
sku|price|user_id|date
1 |5500 |1 | 2021-02-15
1 |5700 |1 | 2021-01-15
2 |4000 |1 | 2021-02-14
3 |8000 |2 | 2021-03-01
4 |400 |2 | 2021-05-12
// ban_list
user_id | date_from
1 | 2021-03-08
Ответ
Используйте DISTINCT по user_id и SKU, а покупки фильтруйте относительно первого бана. Однофамильцев нельзя объединять только по имени.
Считаем, что для незабаненных пользователей подходят все покупки, а для забаненных — строго до первой блокировки:
WITH first_ban AS (
SELECT user_id, MIN(date_from) AS banned_at
FROM ban_list
GROUP BY user_id
)
SELECT DISTINCT u.id, u.firstname, u.lastname, p.sku
FROM "user" u
JOIN purchase p ON p.user_id = u.id
LEFT JOIN first_ban b ON b.user_id = u.id
WHERE b.banned_at IS NULL OR p.date < b.banned_at
ORDER BY u.firstname, u.lastname, p.sku, u.id;
Для данных примера получатся Anna Petrova: SKU 3 и 4; Ivan Petrov с id=1: SKU 1 и 2. Если нужны исключительно пользователи из ban_list, замените LEFT JOIN на JOIN и оставьте только сравнение дат. Повторные баны с разблокировками требуют истории интервалов, отсутствующей в схеме.