Траты по клиенту и доля каждого в выручке, исключая тестовые и возвращённые заказы
Таблица orders(customer_id, amount, status, is_test). Исключите тестовые аккаунты (is_test = true) и возвращённые заказы (status = 'refunded'). Для каждого оставшегося клиента верните суммарные траты и его долю в общей выручке (процент от отфильтрованного общего итога). Доли должны давать в сумме 100%.
-- по клиенту: суммарные траты и доля от отфильтрованного общего итога
Напишите запрос.
Исключают тестовые аккаунты и возвраты в WHERE, суммируют траты по клиенту, затем делят на общий итог: SUM(amount) / SUM(SUM(amount)) OVER () как долю — окно поверх сгруппированных строк. Исключения применяют до обеих сумм, чтобы доли давали 100%.
- ✗Делить на число строк вместо итога выручки
- ✗Фильтровать возвраты в HAVING, а не в WHERE
- ✗Разбивать окно общего итога по customer_id
- →Почему исключения должны быть в WHERE, а не в HAVING?
- →Как ещё показать нарастающую кумулятивную долю?
Filter first, group by customer, and compute the share against the grand total of the filtered revenue. The window SUM(SUM(amount)) OVER () sums the per-customer totals into one grand total available on every grouped row:
SELECT customer_id,
SUM(amount) AS spend,
ROUND(100.0 * SUM(amount) / SUM(SUM(amount)) OVER (), 2) AS pct_share
FROM orders
WHERE is_test = false
AND status <> 'refunded'
GROUP BY customer_id
ORDER BY spend DESC;
The exclusions must sit in WHERE (they filter raw rows before grouping), not HAVING. An equivalent form divides by a scalar subquery:
... SUM(amount) / (SELECT SUM(amount) FROM orders
WHERE is_test = false AND status <> 'refunded') ...
Because every customer's share uses the same filtered denominator, the percentages add up to 100%.