Merge branch 'main' into md_branch
This commit is contained in:
@@ -0,0 +1,90 @@
|
||||
-- 1 Задача
|
||||
SELECT name,
|
||||
CAST(created_at AS date) AS created_date,
|
||||
CURRENT_DATE - CAST(created_at AS date) AS days_since_registration
|
||||
FROM users
|
||||
WHERE created_at <= CURRENT_DATE - INTERVAL '180 days'
|
||||
ORDER BY days_since_registration DESC;
|
||||
-- Ответ на вопросы
|
||||
-- 1. Возможно предложить старым пользователям скидки всякие или интересное предложение для удержания пользователям. Или можно проанализировать их заказы.
|
||||
-- 2. Я предположу что удобней не марочится со временем а сразу работать с датой
|
||||
|
||||
|
||||
-- 2 Задача
|
||||
SELECT name,
|
||||
LOWER(email) AS email_clean,
|
||||
SUBSTRING(LOWER(email) FROM POSITION('@' IN LOWER(email)) + 1) AS domain
|
||||
FROM users
|
||||
WHERE email IS NOT NULL
|
||||
ORDER BY domain, name;
|
||||
-- Ответ на вопросы
|
||||
-- 1. Приводим email к нижнему регистру для чистоты данных,
|
||||
-- а зачем нужен отдельно домен не знаю, может есть какая нибудь важная разница в почтовых сервисах.
|
||||
-- 2. Получим в колонке domain null.
|
||||
|
||||
|
||||
-- 3 Задача
|
||||
SELECT name,
|
||||
age,
|
||||
CASE
|
||||
WHEN age < 25 THEN 'young'
|
||||
WHEN age BETWEEN 25 AND 35 THEN 'adult'
|
||||
WHEN age > 35 THEN 'senior'
|
||||
ELSE 'unknown'
|
||||
END AS age_group
|
||||
FROM users
|
||||
ORDER BY age;
|
||||
-- Ответ на вопросы
|
||||
-- 1. Возможно данные и статистику быстрее и удобнее получить через sql а не через код приложения.
|
||||
-- 2. Пользователи получат null в колонке, оно просто не пройдет условие.
|
||||
|
||||
|
||||
-- 4 Задача
|
||||
SELECT name,
|
||||
created_at::date AS created_date,
|
||||
CURRENT_DATE - created_at::date AS days_since_registration,
|
||||
CASE
|
||||
WHEN is_active = TRUE THEN 'hot'
|
||||
ELSE 'regular'
|
||||
END AS hot_flag
|
||||
FROM users
|
||||
WHERE is_active = TRUE
|
||||
AND created_at >= CURRENT_DATE - INTERVAL '30 days';
|
||||
-- Ответ на вопросы
|
||||
-- 1. В WHERE мы получим только пользователей за последние 30 дней а в CASE мы просто получаем метку 'hot' или 'regular'.
|
||||
-- И в CASE мы не фильтруем по каким либо параметрам а только прописываем условие что записать.
|
||||
-- 2. Какие нибудь рекомендации или скидку на первый заказ.
|
||||
|
||||
|
||||
-- 5 Задача
|
||||
SELECT COUNT(*) AS total_users,
|
||||
COUNT(email) AS with_email,
|
||||
COUNT(*) - COUNT(email) AS without_email,
|
||||
ROUND(COUNT(country) * 100.0 / COUNT(*), 2) AS percentage_users
|
||||
FROM users;
|
||||
-- Ответ на вопросы
|
||||
-- 1. Так гораздо надежнее и правильнее.
|
||||
-- 2. Установить ограничение на создание пользователя, чтоб поле email было не нулевым.
|
||||
|
||||
|
||||
-- 6 Задача
|
||||
SELECT name,
|
||||
CURRENT_DATE - created_at::date AS days_since_registration,
|
||||
CASE
|
||||
WHEN created_at::date >= CURRENT_DATE - INTERVAL '30 days' THEN 'new'
|
||||
WHEN created_at::date < CURRENT_DATE - INTERVAL '30 days'
|
||||
AND created_at::date > CURRENT_DATE - INTERVAL '180 days' THEN 'middle'
|
||||
ELSE 'old'
|
||||
END AS tenure_group,
|
||||
is_active
|
||||
FROM users
|
||||
ORDER BY created_at::date >= CURRENT_DATE - INTERVAL '30 days',
|
||||
created_at::date < CURRENT_DATE - INTERVAL '30 days'
|
||||
AND created_at::date > CURRENT_DATE - INTERVAL '180 days',
|
||||
created_at::date < CURRENT_DATE - INTERVAL '180 days',
|
||||
days_since_registration;
|
||||
-- Ответ на вопросы
|
||||
-- 1. В сегментации по возрасту показывает возраст пользователя,
|
||||
-- а в сегментации стаж показывает на сколько долго пользователь пользуется сервисом(приложением)
|
||||
-- 2. CURRENT_DATE показывает сегодняшний день и если tenure_group пользоваться каждый день, то будет смещатся интервал в логическом выражении CASE.
|
||||
-- В статическом поле дание остаются записанными пока их не изменят, течение времени на них никак не будет влиять.
|
||||
@@ -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. Слишком частые обновления витрит будут сильно нагружать БД.
|
||||
Reference in New Issue
Block a user