diff --git a/vberetar/postgresql/sql_cte.sql b/vberetar/postgresql/sql_cte.sql new file mode 100644 index 0000000..080d9bc --- /dev/null +++ b/vberetar/postgresql/sql_cte.sql @@ -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. Я думаю выгоднее фильтровать внутри подзапроса, чтоб подзапрос не создавал большую таблицу и основному запросу не пришлось ее перебирать.