
Комментарии 8
Задача 1. Топ-3 аптеки по выручке (базовый GROUP BY)
Я бы всё же использовал WITH TIES. И подогнал данные так, чтобы показать, что это даёт.
Пример вывода по данным: Парацетамол лидирует по количеству, так как это дешевый и ходовой товар, но по выручке обезболивающие дают больше.
Из полученных данных этого не видно без дополнительного расчёта в уме. Следовало бы применить WITH ROLLUP.
Пример вывода по данным: Даже пятая аптека дает >10% выручки – все точки важны, нет явных аутсайдеров.
А если есть аптеки, у которых вообще нет продаж, менеджер про это и не узнает, потому что использовал inner join.
Ключевое, кажется, то, что выводим топ по выручке.
Хотя бы правы, может быть важным знаком полное ее отсутствие, если полное отсутствие выручки в целом вообще возможно - стоит его учесть.
Спасибо!
В примере с АВС анализом, для подсчета нарастающего итога вы используете row_number(), хотя можно было сразу его посчитать, добавив фрейм окна в виде ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW. Тогда в CTE второе выражение не потребовалось бы
WITH product_sales AS (
SELECT
pr.product_id,
pr.product_name,
pr.category,
SUM(s.amount) AS revenue,
SUM(SUM(s.amount)) OVER() AS total_revenue,
SUM(SUM(s.amount)) OVER(order BY SUM(s.amount) desc rows between unbounded preceding and current row) as cumulative_revenue
-- ROW_NUMBER() OVER(ORDER BY SUM(s.amount) DESC) AS revenue_rank
FROM sales s
JOIN products pr ON s.product_id = pr.product_id
GROUP BY pr.product_id, pr.product_name, pr.category
)
/*cumulative_calc AS (
SELECT
product_id,
product_name,
category,
revenue,
revenue_rank,
SUM(revenue) OVER(ORDER BY revenue_rank) AS cumulative_revenue,
total_revenue
FROM product_sales
)*/
SELECT
product_name,
category,
revenue,
ROUND(100.0 * revenue / total_revenue, 2) AS revenue_share,
ROUND(100.0 * cumulative_revenue / total_revenue, 2) AS cumulative_share,
CASE
WHEN cumulative_revenue <= 0.7 * total_revenue THEN 'A'
WHEN cumulative_revenue <= 0.9 * total_revenue THEN 'B'
ELSE 'C'
END AS abc_class
FROM product_sales
ORDER BY revenue desc
;
В "Задача 4. Кумулятивные продажи с детализацией (динамика во времени) простой вариант" вы наступаете на те же грабли, не обозначив фрейм для рассчета cumulative_revenue. На примере pharmacy_id =1 это хорошо видно. Так как в 2026-02-01 есть две продажи, а фрейм явно не указан (по умолчанию postgres берет range between). Поэтому для обеих продаж нет нарастания, а дана общая сумма.
SQL для аналитика в ритейле: разбор 4 задач с данными (от простого к сложному)