Merge branch 'main' into vberetar_sql_view
This commit is contained in:
@@ -0,0 +1,105 @@
|
||||
-- Задание 1
|
||||
SELECT category, COUNT(*) AS products_count
|
||||
FROM products
|
||||
GROUP BY category
|
||||
ORDER BY products_count DESC;
|
||||
|
||||
-- Ответ на вопросы
|
||||
-- 1. С ORDER BY гораздо удобней читать результат, без него данные отдаются в непонятном порядке.
|
||||
-- 2. Для категории smartphone добавится +1 значение.
|
||||
|
||||
|
||||
-- Задание 2
|
||||
SELECT order_id,
|
||||
SUM(quantity) AS total_quantity,
|
||||
SUM(quantity * price_at_purchase) AS order_revenue
|
||||
FROM order_items
|
||||
GROUP BY order_id
|
||||
ORDER BY order_revenue DESC;
|
||||
|
||||
-- Ответ на вопросы
|
||||
-- 1. Если убрать GROUP BY и order_id то запрос выдаст 1 строку со всеми суммами total_quantity и order_revenue.
|
||||
-- Если убрать только GROUP BY и не убрать order_id то выдаст ошибку. Так как нельзя оставлять неагрегированные столбцы без GROUP BY.
|
||||
-- 2. Если добавить product_id без добавления её в GROUP BY или агрегат то выдаст ошибку.
|
||||
|
||||
|
||||
-- Задание 3
|
||||
SELECT p.category,
|
||||
SUM(oi.quantity * oi.price_at_purchase) AS category_revenue
|
||||
FROM order_items oi
|
||||
JOIN products p ON p.id = oi.product_id
|
||||
GROUP BY p.category
|
||||
ORDER BY category_revenue;
|
||||
|
||||
-- Ответ на вопросы
|
||||
-- 1. По задаче нам же нужно сгруппировать и посчитать сумму по категориям а не по id товарам.
|
||||
-- 2. Если добавить p.name в SELECT без добавления её в GROUP BY или агрегат то выдаст ошибку. Нельзя вставлять неагрегированные столбцы без GROUP BY.
|
||||
|
||||
|
||||
-- Задание 4
|
||||
SELECT oi.order_id,
|
||||
SUM(oi.quantity * oi.price_at_purchase) AS order_revenue
|
||||
FROM orders o
|
||||
JOIN order_items oi ON oi.order_id = o.id
|
||||
WHERE o.status = 'paid'
|
||||
GROUP BY oi.order_id
|
||||
ORDER BY order_revenue DESC;
|
||||
|
||||
-- Ответ на вопросы
|
||||
-- 1. В этом задании мы получили сумму(выручку) по заказам оплаченным, а в прошлом задании мы получили сумму(выручку) по категориям товаров.
|
||||
-- 2. Посчитать выручку, сколько заработала компания. Остальные заказы еще не оплачены.
|
||||
|
||||
|
||||
-- Задание 5
|
||||
SELECT p.category,
|
||||
SUM(oi.quantity * oi.price_at_purchase) AS category_revenue
|
||||
FROM order_items oi
|
||||
JOIN products p ON p.id = oi.product_id
|
||||
GROUP BY p.category
|
||||
HAVING SUM(oi.quantity * oi.price_at_purchase) > 1000
|
||||
ORDER BY category_revenue;
|
||||
|
||||
-- Ответ на вопросы
|
||||
-- 1. WHERE не принимает агрегирующие функции, можно сделать так - WHERE oi.quantity * oi.price_at_purchase > 1000
|
||||
-- 2. WHERE фильтрует до GROUP BY, а HAVING после GROUP BY.
|
||||
|
||||
|
||||
-- Задание 6
|
||||
SELECT country,
|
||||
COUNT(*) AS active_users_count
|
||||
FROM users
|
||||
WHERE is_active = TRUE
|
||||
GROUP BY country
|
||||
HAVING COUNT(*) > 2
|
||||
ORDER BY active_users_count DESC;
|
||||
|
||||
-- Ответ на вопросы
|
||||
-- 1. Предположу что отбрасывает неактивных пользователей сразу, перед групировкой и агрегаций. В дальнейшем может сэкономить на времени вычисления, особенно если данных будет много.
|
||||
-- 2. Пустую таблицу без строк.
|
||||
|
||||
|
||||
-- Задание 7
|
||||
SELECT p.name AS product_name,
|
||||
SUM(oi.quantity) AS total_quantity_sold
|
||||
FROM order_items oi
|
||||
JOIN products p ON p.id = oi.product_id
|
||||
GROUP BY product_name
|
||||
ORDER BY total_quantity_sold DESC
|
||||
LIMIT 3;
|
||||
|
||||
-- Ответ на вопросы
|
||||
-- 1. Тут мы выясняем какой товар самый ходовой и сколько его продается, а рейтинг по выручке показывает сколько зарабатывает фирма от продажи товара.
|
||||
-- 2. В случаях когда, например, нужно выяснить какой товар хорошо продается чтоб его закупить на склад для продажи.
|
||||
|
||||
|
||||
-- Задание 8
|
||||
SELECT order_id,
|
||||
SUM(quantity * price_at_purchase) AS order_revenue
|
||||
FROM order_items
|
||||
GROUP BY order_id
|
||||
HAVING SUM(quantity * price_at_purchase) < 100
|
||||
ORDER BY order_revenue DESC;
|
||||
|
||||
-- Ответ на вопросы
|
||||
-- 1. Есть товары дешевые и люди которые мало зарабатывают, ещё есть всякие скидки на ряд товаров.
|
||||
-- 2. Я думаю проще увидеть отфильтрованные заказы, чем листать весь список с заказами.
|
||||
@@ -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. Я думаю выгоднее фильтровать внутри подзапроса, чтоб подзапрос не создавал большую таблицу и основному запросу не пришлось ее перебирать.
|
||||
Reference in New Issue
Block a user