Files
homework/mnoskov/postgresql/7. Оконные функции/DQL_window_functions_practice.sql
T
2026-03-11 13:40:31 +03:00

168 lines
5.5 KiB
SQL
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
-- Задание 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;
-- По такому графику мы можем видеть РОСТ выручки по дням например, а не просто сколько в какой день принесла категория