Плановый рекламный бюджет медиаплана по каналам и месяцам
SQL, по которому посчитано
WITH bounds AS (
SELECT date_trunc('month', max(date))::DATE AS end_month
FROM ads
),
months AS (
SELECT (end_month - INTERVAL '2 month')::DATE AS start_month,
end_month
FROM bounds
),
plan_q AS (
SELECT p.month,
p.channel,
p.revenue AS plan_revenue,
p.ad_cost AS plan_ad_cost
FROM plan p
CROSS JOIN months m
WHERE p.month >= m.start_month
AND p.month <= m.end_month
),
ads_map AS (
SELECT date_trunc('month', a.date)::DATE AS month,
CASE a.source
WHEN 'Яндекс Директ' THEN 'Сайт'
WHEN 'VK Реклама' THEN 'Сайт'
WHEN 'Продвижение WB' THEN 'Wildberries'
WHEN 'Продвижение Ozon' THEN 'Ozon'
END AS channel,
sum(a.cost) AS actual_ad_cost
FROM ads a
CROSS JOIN months m
WHERE a.date >= m.start_month
AND a.date < (m.end_month + INTERVAL '1 month')::DATE
GROUP BY 1, 2
),
sales_actual AS (
SELECT date_trunc('month', s.date)::DATE AS month,
s.channel,
sum(s.revenue - s.returned_revenue) AS actual_revenue
FROM sales s
CROSS JOIN months m
WHERE s.date >= m.start_month
AND s.date < (m.end_month + INTERVAL '1 month')::DATE
GROUP BY 1, 2
)
SELECT p.month,
p.channel,
round(p.plan_revenue, 0) AS plan_revenue,
round(coalesce(s.actual_revenue, 0), 0) AS actual_revenue,
round(p.plan_ad_cost, 0) AS plan_ad_cost,
round(coalesce(a.actual_ad_cost, 0), 0) AS actual_ad_cost,
round(100 * p.plan_ad_cost / nullif(p.plan_revenue, 0), 1) AS plan_drr_pct,
round(100 * coalesce(a.actual_ad_cost, 0) / nullif(s.actual_revenue, 0), 1) AS actual_drr_pct,
round(100 * (coalesce(a.actual_ad_cost, 0) - p.plan_ad_cost) / nullif(p.plan_ad_cost, 0), 1) AS ad_cost_deviation_pct,
round(100 * (coalesce(s.actual_revenue, 0) - p.plan_revenue) / nullif(p.plan_revenue, 0), 1) AS revenue_deviation_pct
FROM plan_q p
LEFT JOIN ads_map a
ON a.month = p.month
AND a.channel = p.channel
LEFT JOIN sales_actual s
ON s.month = p.month
AND s.channel = p.channel
ORDER BY p.month, p.channel
LIMIT 30