168 lines
5.5 KiB
SQL
168 lines
5.5 KiB
SQL
-- Задание 1
|
||
SELECT
|
||
o.user_id,
|
||
u.name AS user_name,
|
||
o.id AS order_id,
|
||
o.order_date::date,
|
||
row_number() OVER (PARTITION BY o.user_id ORDER BY o.order_date) AS order_number_for_user
|
||
FROM
|
||
mnoskov.orders o
|
||
JOIN
|
||
mnoskov.users u ON o.user_id = u.id;
|
||
-- Отличае от обычного order by в том, что мы не просто сортируем, а сортируем в пределах одного пользователя, и ещё выводим нумерацию заказов
|
||
|
||
|
||
-- Задание 2
|
||
WITH order_total_revenue AS (
|
||
SELECT
|
||
o.user_id,
|
||
oi.order_id,
|
||
o.order_date::date,
|
||
sum(oi.quantity * oi.price_at_purchase) AS order_revenue
|
||
FROM
|
||
mnoskov.order_items oi
|
||
JOIN
|
||
mnoskov.orders o ON oi.order_id = o.id
|
||
GROUP BY
|
||
o.user_id, oi.order_id, o.order_date
|
||
)
|
||
SELECT
|
||
otr.user_id,
|
||
u.name AS user_name,
|
||
otr.order_id,
|
||
otr.order_date::date,
|
||
otr.order_revenue,
|
||
sum(otr.order_revenue) OVER (PARTITION BY otr.user_id ORDER BY otr.order_date ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS running_revenue_for_user
|
||
FROM
|
||
mnoskov.users u
|
||
JOIN
|
||
order_total_revenue otr ON u.id = otr.user_id;
|
||
-- Если не задвать рамку, то могут пояиться проблемы с дубликатами
|
||
-- Если накопительная выручка пользователя становится больше, значит он начинает тратить больше
|
||
|
||
|
||
-- Задание 3
|
||
WITH user_total_revenue AS (
|
||
SELECT
|
||
o.user_id,
|
||
sum(oi.quantity * oi.price_at_purchase) AS total_revenue
|
||
FROM
|
||
mnoskov.orders o
|
||
JOIN
|
||
mnoskov.order_items oi ON o.id = oi.order_id
|
||
GROUP BY
|
||
o.user_id
|
||
)
|
||
SELECT
|
||
u.name AS user_name,
|
||
utr.total_revenue,
|
||
rank() OVER (ORDER BY utr.total_revenue) AS revenue_rank,
|
||
dense_rank() OVER (ORDER BY utr.total_revenue) AS revenue_dense_rank
|
||
FROM
|
||
mnoskov.users u
|
||
JOIN
|
||
user_total_revenue utr ON u.id = utr.user_id;
|
||
-- Когда появляется одинаковая выручка, dense_rank нумерует по порядку, без пропусков(1,2,2,3), а rank по 'расположению'(1,2,2,4)
|
||
|
||
|
||
-- Задание 4
|
||
SELECT
|
||
u.name AS user_name,
|
||
o.id AS order_id,
|
||
o.order_date::date,
|
||
first_value(o.order_date::date) OVER (PARTITION BY u.id ORDER BY o.order_date) AS first_order_date,
|
||
last_value(o.order_date::date) OVER (PARTITION BY u.id ORDER BY o.order_date ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS last_order_date
|
||
FROM
|
||
mnoskov.orders o
|
||
JOIN
|
||
mnoskov.users u ON o.user_id = u.id;
|
||
-- Первый заказ можно использовать для отчета 'как давно клиент начал активничать', а последний заказ, например если давно был последний заказ, то кинуть рассылку с промокодом, чтобы клиент снова начала заказывать как вариант
|
||
-- Если не задать рамку, то дата последнего заказа будет равна текущей строке, а не последней
|
||
|
||
|
||
-- Задание 5
|
||
SELECT
|
||
u.name AS user_name,
|
||
o.id AS order_id,
|
||
count(*) OVER (PARTITION BY u.id) AS orders_per_user
|
||
FROM
|
||
mnoskov.orders o
|
||
JOIN
|
||
mnoskov.users u ON o.user_id = u.id;
|
||
-- Если использовать просто group by, то пользователи сожмутся в одну ячейку
|
||
|
||
|
||
-- Задание 6
|
||
WITH order_total_revenue AS (
|
||
SELECT
|
||
o.user_id,
|
||
oi.order_id,
|
||
o.order_date::date,
|
||
sum(oi.quantity * oi.price_at_purchase) AS order_revenue
|
||
FROM
|
||
mnoskov.orders o
|
||
JOIN
|
||
mnoskov.order_items oi ON o.id = oi.order_id
|
||
GROUP BY
|
||
o.user_id, oi.order_id, o.order_date
|
||
)
|
||
SELECT
|
||
u.name AS user_name,
|
||
otr.order_id,
|
||
otr.order_date::date,
|
||
otr.order_revenue,
|
||
lag(otr.order_revenue) OVER (PARTITION BY u.id ORDER BY otr.order_date) AS prev_order_revenue
|
||
FROM
|
||
mnoskov.users u
|
||
JOIN
|
||
order_total_revenue otr ON u.id = otr.user_id;
|
||
-- если текущее значение среднего чека больше чем предидущие, то увеличивается, а если наоборот, то уменьшается
|
||
|
||
|
||
-- Задание 7
|
||
-- По месяцам:
|
||
WITH category_total_revenue AS (
|
||
SELECT
|
||
p.category,
|
||
date_trunc('month', o.order_date)::date AS order_date_month,
|
||
sum(oi.quantity * oi.price_at_purchase) AS monthly_category_revenue
|
||
FROM
|
||
mnoskov.products p
|
||
JOIN
|
||
mnoskov.order_items oi ON p.id = oi.product_id
|
||
JOIN
|
||
mnoskov.orders o ON oi.order_id = o.id
|
||
GROUP BY
|
||
p.category, order_date_month
|
||
)
|
||
SELECT
|
||
category,
|
||
order_date_month,
|
||
monthly_category_revenue,
|
||
sum(monthly_category_revenue) OVER (PARTITION BY category ORDER BY order_date_month ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS running_category_revenue
|
||
FROM
|
||
category_total_revenue;
|
||
|
||
-- По дням:
|
||
WITH category_total_revenue AS (
|
||
SELECT
|
||
p.category,
|
||
o.order_date::date AS order_date,
|
||
sum(oi.quantity * oi.price_at_purchase) AS daily_category_revenue
|
||
FROM
|
||
mnoskov.products p
|
||
JOIN
|
||
mnoskov.order_items oi ON p.id = oi.product_id
|
||
JOIN
|
||
mnoskov.orders o ON oi.order_id = o.id
|
||
GROUP BY
|
||
p.category, order_date
|
||
)
|
||
SELECT
|
||
category,
|
||
order_date,
|
||
daily_category_revenue,
|
||
sum(daily_category_revenue) OVER (PARTITION BY category ORDER BY order_date ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS running_category_revenue
|
||
FROM
|
||
category_total_revenue;
|
||
-- По такому графику мы можем видеть РОСТ выручки по дням например, а не просто сколько в какой день принесла категория |