работа над ошибками по Создание таблиц, JOIN, UNION, Агреции и группировки, Функции, CTE.

This commit is contained in:
mnoskov
2026-03-15 21:56:20 +03:00
parent ed2b990a36
commit 240ccccba3
6 changed files with 17 additions and 19 deletions
@@ -28,12 +28,10 @@ DROP TABLE IF EXISTS mnoskov.orders;
CREATE TABLE mnoskov.orders ( CREATE TABLE mnoskov.orders (
id bigint PRIMARY KEY, id bigint PRIMARY KEY,
user_id bigint, user_id bigint,
order_date date NOT NULL, -- в названии date, и тип думаю date order_date timestamptz NOT NULL, -- в названии date, и тип думаю date
status varchar(20), -- думал лучше int, но судя по заданию DML лучше varchar status varchar(20), -- думал лучше int, но судя по заданию DML лучше varchar
FOREIGN KEY (user_id) REFERENCES users(id) FOREIGN KEY (user_id) REFERENCES users(id)
); );
ALTER TABLE mnoskov.orders
ALTER COLUMN order_date TYPE timestamptz;
-- Задание 4 -- Задание 4
@@ -16,7 +16,7 @@ LEFT JOIN
-- Задание 2 -- Задание 2
SELECT SELECT
oi.order_id, oi.order_id,
p.name AS prouct_name, p.name AS product_name,
oi.quantity, oi.quantity,
oi.price_at_purchase oi.price_at_purchase
FROM FROM
@@ -75,7 +75,7 @@ WHERE
-- Задание 6 -- Задание 6
SELECT SELECT
oi.order_id, oi.order_id,
u.id AS user_name, u.id AS user_id,
p.name AS product_name, p.name AS product_name,
oi.quantity oi.quantity
FROM FROM
@@ -70,6 +70,6 @@ FROM
mnoskov.products p mnoskov.products p
LEFT JOIN LEFT JOIN
mnoskov.order_items oi ON p.id = oi.product_id mnoskov.order_items oi ON p.id = oi.product_id
WHERE oi.product_id = NULL; WHERE oi.product_id is NULL;
-- Проверка IS NULL по полю из order_items, потому что это права таблица, и null будут добавляться в неё -- Проверка IS NULL по полю из order_items, потому что это права таблица, и null будут добавляться в неё
-- 1) Понизить цену товара 2) лучше прорекламировать 3) снять с продажи -- 1) Понизить цену товара 2) лучше прорекламировать 3) снять с продажи
@@ -93,7 +93,7 @@ HAVING
count(*) >= 2 count(*) >= 2
ORDER BY ORDER BY
active_user_count DESC; active_user_count DESC;
-- is_active = true логичнее писать в HAVING, потому что is_active - не агрегат -- is_active = true логичнее писать в WHERE, потому что is_active - не агрегат
-- Если нет страны где больше двух активных юзеров, то ничего не выведется -- Если нет страны где больше двух активных юзеров, то ничего не выведется
@@ -126,5 +126,5 @@ HAVING
sum(quantity * price_at_purchase) < 10000 sum(quantity * price_at_purchase) < 10000
ORDER BY ORDER BY
order_revenue; order_revenue;
-- Не понял вопрос: Какие реальные причины могут быть у очень маленьких заказов (1–2 гипотезы)? -- Не понял вопрос: Какие реальные причины могут быть у очень маленьких заказов (1–2 гипотезы)? Ответ: «доставка пробников/тестовой партии», «использование купонов/бонусов», «технический тест витрины»
-- Проще увидеть глазами отфильтрованные микро-заказы -- Проще увидеть глазами отфильтрованные микро-заказы
@@ -40,7 +40,7 @@ FROM
mnoskov.users mnoskov.users
ORDER BY ORDER BY
age; age;
-- Почему удобнее держать логику сегментации в SQL (CASE), а не только в коде приложения? Я не понял этот вопрос. -- Почему удобнее держать логику сегментации в SQL (CASE), а не только в коде приложения? В каком коде? Если в 'коде приложения' - это какая-то отдельная программа, то могут предположить, чтобы передавать в приложение уже отфильтрованные данные, чтобы задачи базы данных не выносить из базы.
-- Если забыть в ветку ELSE, то будет NULL у тех кто никуда не попал -- Если забыть в ветку ELSE, то будет NULL у тех кто никуда не попал
@@ -50,7 +50,7 @@ SELECT
created_at::date, created_at::date,
current_date - created_at::date AS days_since_registration, current_date - created_at::date AS days_since_registration,
CASE CASE
WHEN created_at >= current_date - INTERVAL '30 days' THEN 'hot' ELSE 'regular' WHEN created_at >= current_date - INTERVAL '30 days' THEN 'hot' ELSE NULL
END AS hot_flag END AS hot_flag
FROM FROM
mnoskov.users mnoskov.users
@@ -26,7 +26,7 @@ WHERE NOT EXISTS (
WHERE WHERE
u.id = o.user_id u.id = o.user_id
) )
-- Работает быстрее чем NOT IN -- NOT EXISTS безопаснее в плане NULL, и часто планируется лучше чем NOT IN
-- Определить какое количество людей не делают заказы, и кинуть им например купон на скидку на первый заказ -- Определить какое количество людей не делают заказы, и кинуть им например купон на скидку на первый заказ
@@ -50,7 +50,7 @@ ORDER BY
-- Задание 4 -- Задание 4
WITH revenue_by_user AS ( WITH revenue_user AS (
SELECT SELECT
o.user_id, o.user_id,
sum(oi.quantity * oi.price_at_purchase) AS total_revenue sum(oi.quantity * oi.price_at_purchase) AS total_revenue
@@ -63,19 +63,19 @@ WITH revenue_by_user AS (
) )
SELECT SELECT
u.name, u.name,
rbu.total_revenue ru.total_revenue
FROM FROM
mnoskov.users u mnoskov.users u
JOIN JOIN
revenue_by_user rbu ON u.id = rbu.user_id revenue_user ru ON u.id = ru.user_id
ORDER BY ORDER BY
rbu.total_revenue desc; ru.total_revenue desc;
-- Проще читать когда шаг «посчитать выручку по пользователям» вынесен отдельно -- Проще читать когда шаг «посчитать выручку по пользователям» вынесен отдельно
-- Чтобы избежать дублирования импользуется CTE, а не простой подзапрос -- Чтобы избежать дублирования импользуется CTE, а не простой подзапрос
-- Задание 5 -- Задание 5
WITH revenue_by_product AS ( WITH revenue_product AS (
SELECT SELECT
product_id, product_id,
sum(quantity * price_at_purchase) AS product_revenue sum(quantity * price_at_purchase) AS product_revenue
@@ -87,13 +87,13 @@ WITH revenue_by_product AS (
SELECT SELECT
p.name, p.name,
p.category, p.category,
rbp.product_revenue rp.product_revenue
FROM FROM
mnoskov.products p mnoskov.products p
JOIN JOIN
revenue_by_product rbp ON p.id = rbp.product_id revenue_product rp ON p.id = rp.product_id
ORDER BY ORDER BY
rbp.product_revenue rp.product_revenue
LIMIT 3; LIMIT 3;
-- Сначала удобнее считать агрегаты, чтобы код не выгляжел грооздким и чтобы в нем было легче разобраться -- Сначала удобнее считать агрегаты, чтобы код не выгляжел грооздким и чтобы в нем было легче разобраться
-- Отличае в удобстве чтения и написания. И этот агрегат можно потом ещё и переиспользовать -- Отличае в удобстве чтения и написания. И этот агрегат можно потом ещё и переиспользовать