Доля дублей и неполных сделок по месяцам. Вымышленный мебельный магазин
SQL, по которому посчитано
WITH bounds AS (
SELECT date_trunc('month', max(date)) AS max_month
FROM deals
),
months AS (
SELECT t.month::DATE AS month
FROM bounds,
generate_series(bounds.max_month - INTERVAL '11 months', bounds.max_month, INTERVAL '1 month') AS t(month)
),
base AS (
SELECT deal_id, customer_id, date, manager, category, amount
FROM deals
WHERE date >= (SELECT min(month) FROM months)
AND date < (SELECT max(month) + INTERVAL '1 month' FROM months)
),
dup_groups AS (
SELECT customer_id, date, amount, category, count(*) AS cnt
FROM base
WHERE customer_id IS NOT NULL
AND amount IS NOT NULL
GROUP BY customer_id, date, amount, category
HAVING count(*) > 1
),
dup_deals AS (
SELECT date, sum(cnt - 1)::INTEGER AS duplicate_deals
FROM dup_groups
GROUP BY date
),
incomplete_monthly AS (
SELECT date_trunc('month', date)::DATE AS month,
CAST(count(*) FILTER (
WHERE customer_id IS NULL
OR manager IS NULL
OR amount IS NULL
OR amount <= 0
) AS INTEGER) AS incomplete_deals
FROM base
GROUP BY 1
),
daily AS (
SELECT date, count(*) AS deals_count
FROM base
GROUP BY date
),
monthly AS (
SELECT m.month,
coalesce(sum(d.deals_count), 0)::INTEGER AS deals_count,
coalesce(sum(dd.duplicate_deals), 0)::INTEGER AS duplicate_deals,
date_diff('day', m.month, m.month + INTERVAL '1 month') - count(DISTINCT d.date) AS days_without_deals,
coalesce(im.incomplete_deals, 0)::INTEGER AS incomplete_deals
FROM months m
LEFT JOIN daily d ON date_trunc('month', d.date)::DATE = m.month
LEFT JOIN dup_deals dd ON dd.date = d.date
LEFT JOIN incomplete_monthly im ON im.month = m.month
GROUP BY m.month, im.incomplete_deals
)
SELECT
month,
deals_count,
duplicate_deals,
days_without_deals,
incomplete_deals,
round(
CASE WHEN deals_count = 0 THEN 0
ELSE duplicate_deals::DOUBLE / deals_count
END, 4
) AS duplicate_share,
round(
CASE WHEN deals_count = 0 THEN 0
ELSE incomplete_deals::DOUBLE / deals_count
END, 4
) AS incomplete_share
FROM monthly
ORDER BY month