-- Задача 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. Я думаю выгоднее фильтровать внутри подзапроса, чтоб подзапрос не создавал большую таблицу и основному запросу не пришлось ее перебирать.