Files
homework/mnoskov/postgresql/6. Подзапросы и CTE/DQL_cte_practice.sql
T
2026-03-10 17:23:31 +03:00

155 lines
4.0 KiB
SQL

-- Задание 1
SELECT
name
FROM
mnoskov.users
WHERE id IN (
SELECT user_id
FROM mnoskov.orders
)
ORDER BY
name;
-- Тут не приходится делать JOIN и DISTINCT, а просто ищем айдишник в списке
-- N (подзапрос) может быть более читаемым, когда подзапрос очень простой и короткий
-- Задание 2
SELECT
u.id,
u.name,
u.email
FROM
mnoskov.users u
WHERE NOT EXISTS (
SELECT user_id
FROM mnoskov.orders o
WHERE
u.id = o.user_id
)
-- Работает быстрее чем NOT IN
-- Определить какое количество людей не делают заказы, и кинуть им например купон на скидку на первый заказ
-- Задание 3
SELECT
u.name,
(
SELECT
count(*)
FROM
mnoskov.orders o
WHERE
u.id = o.user_id
) AS orders_count
FROM
mnoskov.users u
ORDER BY
orders_count DESC, u.name;
-- Подзапрос в SELECT не может возвращать несколько строк, потому что SELECT ожидает толбко одну
-- Как изменится сложность запроса, если пользователей станет, например, 1 млн? Не совсем понял этот вопрос, но думаю запрос просто будет выполняться дольше
-- Задание 4
WITH revenue_by_user 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,
rbu.total_revenue
FROM
mnoskov.users u
JOIN
revenue_by_user rbu ON u.id = rbu.user_id
ORDER BY
rbu.total_revenue desc;
-- Проще читать когда шаг «посчитать выручку по пользователям» вынесен отдельно
-- Чтобы избежать дублирования импользуется CTE, а не простой подзапрос
-- Задание 5
WITH revenue_by_product AS (
SELECT
product_id,
sum(quantity * price_at_purchase) AS product_revenue
FROM
mnoskov.order_items
GROUP BY
product_id
)
SELECT
p.name,
p.category,
rbp.product_revenue
FROM
mnoskov.products p
JOIN
revenue_by_product rbp ON p.id = rbp.product_id
ORDER BY
rbp.product_revenue
LIMIT 3;
-- Сначала удобнее считать агрегаты, чтобы код не выгляжел грооздким и чтобы в нем было легче разобраться
-- Отличае в удобстве чтения и написания. И этот агрегат можно потом ещё и переиспользовать
-- Задание 6
WITH revenue_user AS (
SELECT
o.user_id,
sum(oi.quantity * oi.price_at_purchase) AS total_revenue
FROM
mnoskov.order_items oi
JOIN
mnoskov.orders o ON oi.order_id = o.id
GROUP BY
o.user_id
)
SELECT
u.name,
u.email,
ru.total_revenue
FROM
mnoskov.users u
JOIN
revenue_user ru ON u.id = ru.user_id
WHERE
u.is_active = TRUE AND
ru.total_revenue > 10000
ORDER BY
ru.total_revenue DESC, u.name;
-- Я бы назвал этот сегмегт - frequent_buyers
-- Таким пользователям надо предлагать какую ниюудь специальную программу лояльности
-- Задание 7
WITH revenue_order AS (
SELECT
order_id,
sum(quantity * price_at_purchase) AS order_revenue
FROM
mnoskov.order_items
GROUP BY
order_id
)
SELECT
ro.order_id,
o.order_date::date,
ro.order_revenue
FROM
mnoskov.orders o
JOIN
revenue_order ro ON o.id = ro.order_id
WHERE
o.status = 'paid' AND
ro.order_revenue < 10000
ORDER BY
ro.order_revenue;
-- Причины: злоупотребление промокодами, ошибки
-- По 'paid' удобнее фильтровать снаржуи, потому тут мы подключаем orders, а подключать orders ещё и внутри было бы бессмысленно