практика Оконные функции
This commit is contained in:
@@ -0,0 +1,168 @@
|
|||||||
|
-- Задание 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;
|
||||||
|
-- По такому графику мы можем видеть РОСТ выручки по дням например, а не просто сколько в какой день принесла категория
|
||||||
Reference in New Issue
Block a user