Задача не выглядит эффектно, зато постоянно встречается при разработке витрин.
🟫 Допустим, в одной строке за каждый месяц нужно получить:
• общее число заказов;
• число оплаченных заказов;
• долю оплаченных;
• выручку по оплатам.
Похожая задача есть и в моём курсе SQL Middle.
Можно написать несколько подзапросов, посчитать в каждом свою метрику, а потом соединить результаты. Но для такой задачи это лишняя конструкция.
☕️ Я обычно использую условную агрегацию через
SUM(CASE WHEN ...):select
date_trunc('month', created_at)::date as month_start,
count(*) as total_orders,
sum(
case
when status = 'paid' then 1
else 0
end
) as paid_orders,
round(
100.0 * sum(
case
when status = 'paid' then 1
else 0
end
) / count(*), 1
) as paid_share,
sum(
case
when status = 'paid' then amount
else 0
end
) as paid_revenue
from orders
group by 1
order by 1;
Каждый
CASE решает, какие строки попадут в конкретную метрику. Все метрики считаются в рамках одной агрегации, без отдельных подзапросов и JOIN между их результатами.Главное, не выносить
status = 'paid' в общий WHERE. Иначе неоплаченные заказы исчезнут ещё до агрегации, а доля оплат получится бессмысленной.✅ В PostgreSQL ту же логику можно записать короче через
FILTER:count(*) filter (where status = 'paid')
В конкретной задаче это аналог:
sum(case when status = 'paid' then 1 else 0 end)
Мне чаще удобнее
SUM(CASE WHEN ...): конструкция читается буквально и поддерживается разными СУБД. Но для PostgreSQL вариант с FILTER тоже вполне рабочий.Такой шаблон подходит не только для заказов. Тем же способом считаются этапы воронки, статусы событий, категории ошибок и результаты проверок качества данных.
Ставь реакцию:
🔥 - знаю и применяю конструкцию
🤔 - узнал новое
#база_знаний
