homework, pet project DE Dmitry_Medvedev #1

Open
dmitry_medvedev wants to merge 264 commits from md_branch into main
2 changed files with 187 additions and 0 deletions
Showing only changes of commit de43c2f290 - Show all commits
+118
View File
@@ -0,0 +1,118 @@
-- Задача 1
SELECT u.name
FROM users u
WHERE id IN (
SELECT o.user_id
FROM orders o
)
ORDER BY u.name;
-- Ответ на вопросы
-- 1. JOIN склеивает одну таблицу со второй, а подзапрос с IN выполняет запрос и получает список с user_id,
-- далее по этому списку отфильтровывает пользователей в основном запросе.
-- 2. Когда запрос простой и короткий.
-- Задача 2
SELECT u.id,
u.name,
u.email
FROM users u
WHERE NOT EXISTS (
SELECT 1
FROM orders o
WHERE o.user_id = u.id
);
-- Ответ на вопросы
-- 1. Предположу что NOT EXISTS более бещопасно работает с null.
-- 2. Отправить таким пользователям рекомендацию, специальный промокод на скидку для первого заказа или рекламу.
-- Задача 3
SELECT u.name,
(
SELECT COUNT(*)
FROM orders o
WHERE u.id = o.user_id
) AS orders_count
FROM users u
ORDER BY orders_count DESC, name;
-- Ответ на вопросы
-- 1. Если подзапрос SELECT вернётся две и более строки то будет ошибка.
-- 2. Сложность возрастет и скорее всего нужно будет оптимизировать запрос.
-- Задача 4
WITH total_revenue_cte AS (
SELECT o.user_id,
SUM(oi.quantity * oi.price_at_purchase) AS total_price
FROM orders o
JOIN order_items oi ON oi.order_id = o.id
GROUP BY o.user_id
)
SELECT u.name,
trc.total_price AS total_revenue
FROM users u
JOIN total_revenue_cte trc ON trc.user_id = u.id
ORDER BY total_revenue DESC;
-- Ответ на вопросы
-- 1. Проще читать запрос "посчитать выручку по пользователям" когда вынесен отдельно.
-- 2. Вроде как в postgres можно в базу данных записывать функции, если я ничего не путаю.
-- И далее вызывать эту функцию при необходимости, так можно избежать дублирования кода.
-- Задача 5
WITH product_price_at_purchase_cte AS (
SELECT oi.product_id,
SUM(oi.quantity * oi.price_at_purchase) AS product_revenue
FROM order_items oi
GROUP BY oi.product_id
)
SELECT p.name AS product_name,
p.category,
ppps.product_revenue
FROM products p
JOIN product_price_at_purchase_cte ppps ON ppps.product_id = p.id
ORDER BY ppps.product_revenue DESC
LIMIT 3;
-- Ответ на вопросы
-- 1. Возможно потому что products оcновная таблица, сналчала нужно из order_items достать агрегацию по id а потом склеивать с products.
-- 2. Через CTE мы получаем готовую таблицу и далее делаем с ней что хотим,
-- а в гуруппировке через GROUP BY нельзя добавить дополнительные поля name и category.
-- Задача 6
WITH total_revenue_cte AS (
SELECT o.user_id,
SUM(oi.quantity * oi.price_at_purchase) AS total_revenue
FROM orders o
JOIN order_items oi ON oi.order_id = o.id
GROUP BY o.user_id
)
SELECT u.name,
u.email,
trc.total_revenue
FROM users u
JOIN total_revenue_cte trc ON trc.user_id = u.id
WHERE u.is_active = TRUE AND trc.total_revenue > 1000
ORDER BY total_revenue DESC;
-- Ответ на вопросы
-- 1. Думаю как то так - user_most_expenses
-- 2. Можно предлагать рекламу товаров, анализировать что пользователи покупали и потом предлагать схожую продукцию.
WITH order_revenue_cte AS (
SELECT order_id,
SUM(quantity * price_at_purchase) AS order_revenue
FROM order_items
GROUP BY order_id
)
SELECT o.id,
o.order_date,
oc.order_revenue
FROM orders o
JOIN order_revenue_cte oc ON oc.order_id = o.id
WHERE o.status = 'paid' AND oc.order_revenue < 100;
-- Ответ на вопросы
-- 1. Какие реальные причины таких заказов, я думаю что просто не все люди богатые что бы заказывать на большие суммы (если я правильно понял статус paid)
-- Чтобы узнать злоупотребления промокодами нужно копаться в других данных, где хранятся данные о введенных промокодах.
-- 2. Я думаю выгоднее фильтровать внутри подзапроса, чтоб подзапрос не создавал большую таблицу и основному запросу не пришлось ее перебирать.
+69
View File
@@ -0,0 +1,69 @@
-- Задание 1
CREATE MATERIALIZED VIEW my_category_revenue AS
SELECT
p.category,
SUM(oi.quantity * oi.price_at_purchase) AS total_revenue
FROM orders o
JOIN order_items oi ON oi.order_id = o.id
JOIN products p ON p.id = oi.product_id
WHERE o.status = 'paid'
GROUP BY p.category;
SELECT * FROM my_category_revenue
ORDER BY total_revenue DESC;
-- Ответ на вопросы
-- 1. Не нужно писать длинные запросы и результат будет уже подсчитан.
-- Задание 2
CREATE MATERIALIZED VIEW mv_user_activity AS
SELECT
u.id AS user_id,
u.name AS user_name,
COUNT(o.user_id) AS orders_count
FROM users u
LEFT JOIN orders o ON u.id = o.user_id AND o.status = 'paid'
GROUP BY u.id, u.name;
SELECT * FROM mv_user_activity
WHERE orders_count > 0
ORDER BY orders_count DESC;
-- Ответ на вопросы
-- 1. Я так понял, что если критерий "самых лояльных" клиентов это колличество оплаченных заказов,
-- то "самые лояльные" это те у кого этих заказов больше всего.
-- 2. Покажет "самых лояльных" клиентов за последный месяц, кто-то из клиетов может сделать много заказов за 1-2 месяца, а кто то за год по чуть чуть заказывает.
-- Возможно еще какие то из клиентов ориентируются на "сезонные" товары и у них будет сплеск продажи за последний месяц, или кто то из клиентов покупал много за год, а в этом месяце перестал делать заказы.
-- Задание 3
CREATE MATERIALIZED VIEW mv_daily_revenue AS
SELECT
o.order_date::date AS sales_date,
SUM(oi.quantity * price_at_purchase) AS daily_revenue
FROM orders o
JOIN order_items oi ON oi.order_id = o.id
WHERE o.status = 'paid'
GROUP BY o.order_date::date;
SELECT * FROM mv_daily_revenue
ORDER BY sales_date DESC;
-- Ответ на вопросы
-- 1. «Просадки» и «пики» будут видны в колонке daily_revenue
-- 2. Быстрее считывать с готовой витрины mv_daily_revenuе, на лету из сырых таблиц дольше будет обрабатываться запрос.
-- Задание 4
REFRESH MATERIALIZED VIEW mv_daily_revenue;
-- Расписание интернет‑магазина с несколькими заказами в день:
-- Для такого сценария подойдет обновление витрины раз в неделю по ночам.
-- Так как заказов не так уж и много, можно обновлять статискиту чаще.
-- Ночью, потому что заказов будет меньше в то время суток и бд быстрее обработает ззапрос.
-- Расписание крупного магазина с тысячами заказов в час:
-- Для такого сценария подойдет обновление витрин раз в месяц - раз в квартал по ночам,
-- Так как данных много и частые расчеты будут сильно нагружать базу данных.
-- Возможно, нужно будет получить данные аналитикам раньше указанных сроков.
-- Ответ на вопросы
-- 1. Данные будут устаревшими, из за того результат работы аналитиков будут не достоверными.
-- 2. Слишком частые обновления витрит будут сильно нагружать БД.