All homework SQL2.0 done in one file
This commit is contained in:
@@ -0,0 +1,523 @@
|
||||
-----------------------------------------------------------
|
||||
--DDL
|
||||
create table users (
|
||||
id INT primary key not null,
|
||||
name VARCHAR(100),
|
||||
age INT,
|
||||
email VARCHAR(100),
|
||||
country VARCHAR(50),
|
||||
is_active BOOLEAN,
|
||||
created_at DATE
|
||||
);
|
||||
|
||||
create table products (
|
||||
id INT primary key,
|
||||
name VARCHAR(100) not null,
|
||||
category VARCHAR(50),
|
||||
price DECIMAL(10, 2) not null,
|
||||
in_stock BOOLEAN
|
||||
);
|
||||
|
||||
create table orders (
|
||||
id INT primary key,
|
||||
user_id INT,
|
||||
order_date DATE not null,
|
||||
status VARCHAR(20)
|
||||
);
|
||||
|
||||
create table order_items (
|
||||
order_id INT,
|
||||
product_id INT,
|
||||
quantity INT not null,
|
||||
price_at_purchase DECIMAL(10, 2) not null,
|
||||
primary key (order_id, product_id)
|
||||
);
|
||||
|
||||
alter table users
|
||||
alter column created_at type timestamptz;
|
||||
|
||||
--------------------------------------------------------------------------------------
|
||||
-- DML
|
||||
INSERT INTO users (id, name, age, email, country, is_active, created_at)
|
||||
VALUES
|
||||
(1, 'Alice', 25, 'alice@example.com', 'US', true, '2024-01-10 10:00:00'),
|
||||
(2, 'Bob', 30, 'bob@example.com', 'UK', true, '2024-02-05 09:30:00'),
|
||||
(3, 'Carol', 27, 'carol@example.com', 'US', false, '2024-03-01 15:20:00'),
|
||||
(4, 'Diana', 22, 'diana@GMAIL.com', 'US', true, '2024-01-12 08:15:00'),
|
||||
(5, 'Evan', 35, 'EVAN@example.com', 'UK', true, '2024-01-18 19:40:00'),
|
||||
(6, 'Farida', 29, 'farida@example.com', 'KZ', true, '2024-02-20 11:05:00'),
|
||||
(7, 'George', 31, 'george+test@example.com', 'US', true, '2024-03-05 16:45:00'),
|
||||
(8, 'Helen', 24, NULL, 'UK', false, '2024-03-06 08:20:00'),
|
||||
(9, 'Ivan', 26, 'ivan@example.com', 'RU', true, '2024-01-11 14:30:00'),
|
||||
(10, 'Julia', 28, 'julia@example.com', 'US', true, '2024-03-07 18:05:00');
|
||||
|
||||
|
||||
INSERT INTO products (id, name, category, price, in_stock)
|
||||
VALUES
|
||||
(1, 'iPhone 15', 'Электроника', 80000, true),
|
||||
(2, 'Kindle', 'Электроника', 15000, true),
|
||||
(3, 'Кроссовки Nike', 'Одежда', 9000, true),
|
||||
(4, 'Кроссовки NoName', 'Одежда', 3000, false),
|
||||
(5, 'Наушники Pro', 'Электроника', 12000, true),
|
||||
(6, 'Фитнес‑браслет', 'Гаджеты', 6000, true),
|
||||
(7, 'Подарочная карта', 'Сервисы', 1000, true);
|
||||
|
||||
|
||||
INSERT INTO orders (id, user_id, order_date, status)
|
||||
VALUES
|
||||
(1, 1, '2025-01-10 12:00:00', 'paid'),
|
||||
(2, 3, '2025-01-12 09:30:00', 'cancelled'),
|
||||
(3, 1, '2025-01-15 18:20:00', 'paid'),
|
||||
(4, 2, '2025-01-20 11:05:00', 'created'),
|
||||
(5, 4, '2025-02-01 17:45:00', 'paid'),
|
||||
(6, 5, '2025-02-10 10:10:00', 'refunded'),
|
||||
(7, 7, '2025-03-01 09:00:00', 'paid'),
|
||||
(8, 9, '2025-03-05 19:30:00', 'paid');
|
||||
|
||||
|
||||
INSERT INTO order_items (order_id, product_id, quantity, price_at_purchase)
|
||||
VALUES
|
||||
(1, 1, 1, 78000),
|
||||
(1, 3, 2, 8500),
|
||||
(2, 2, 1, 14000),
|
||||
(3, 5, 1, 11000),
|
||||
(3, 7, 1, 1000),
|
||||
(4, 2, 1, 15000),
|
||||
(5, 6, 1, 6000),
|
||||
(6, 1, 1, 82000),
|
||||
(7, 3, 1, 9000),
|
||||
(8, 4, 2, 2800);
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------------------
|
||||
--BASE SQL
|
||||
select id, name, country, created_at, email from users
|
||||
order by created_at desc, name;
|
||||
|
||||
select id, name, country from users
|
||||
where country = 'US' -- 'UK'
|
||||
order by name;
|
||||
|
||||
select id, name, email from users
|
||||
where email is not null
|
||||
order by name;
|
||||
|
||||
select distinct LOWER(email) as email_lower from users
|
||||
where email is not null;
|
||||
|
||||
select id, name, created_at from users
|
||||
where created_at > '2024-01-11'
|
||||
order by created_at desc
|
||||
limit 2 offset 1;
|
||||
------------------------------------------------------------------------------------------------------
|
||||
-- FILTRATION
|
||||
select name, category, price,
|
||||
price * 1.3 as price_with_markup,
|
||||
price * 1.5 as price_with_vat from products
|
||||
where in_stock is true
|
||||
and category not in ('Гаджеты')
|
||||
and price >= 100 and price <=1300;
|
||||
|
||||
select name, price,
|
||||
price * 0.85 as price_with_discount
|
||||
from products
|
||||
where price < 100 or price > 1000;
|
||||
|
||||
select id, name, category, price from products
|
||||
where category in ('Электроника') and price >= 15000;
|
||||
|
||||
select name, category, price from products
|
||||
where name not like '%iPhone%';
|
||||
|
||||
select * from products
|
||||
where name ilike '%pro%';
|
||||
|
||||
---------------------------------------------------------------------------------------------------
|
||||
-- JOIN
|
||||
-- 1 задание
|
||||
select o.id as order_id, order_date, status, u.name as user_name, country from orders o
|
||||
join users u on o.user_id = u.id;
|
||||
|
||||
-- 2 задание
|
||||
|
||||
select o.id as order_id, p.name as product_name, oi.quantity, oi.price_at_purchase from orders o
|
||||
join order_items oi on o.id = oi.order_id
|
||||
join products p on oi.product_id = p.id
|
||||
where o.id = 1;
|
||||
|
||||
-- 3 задание
|
||||
select o.id as order_id, p.name as product_name, oi.quantity, oi.price_at_purchase from orders o
|
||||
join order_items oi on o.id = oi.order_id
|
||||
join products p on oi.product_id = p.id;
|
||||
|
||||
-- 4 задание
|
||||
select u.name as user_name, o.id as order_id, o.status from users u
|
||||
left join orders o on u.id = o.user_id;
|
||||
|
||||
-- 5 задание
|
||||
select u.id as user_id, u.name as user_name from users u
|
||||
left join orders o on u.id = o.user_id
|
||||
where o.user_id is null;
|
||||
|
||||
-- 6 задание
|
||||
|
||||
select o.id as order_id, p.name as product_name, oi.quantity, oi.price_at_purchase from orders o
|
||||
join order_items oi on o.id = oi.order_id
|
||||
join products p on oi.product_id = p.id
|
||||
where p.name = 'Фитнес‑браслет';
|
||||
|
||||
-- 7 задание
|
||||
|
||||
select o.id as order_id, p.name as product_name, oi.quantity, oi.price_at_purchase from orders o
|
||||
join order_items oi on o.id = oi.order_id
|
||||
join products p on oi.product_id = p.id
|
||||
where o.status = 'paid';
|
||||
|
||||
-- 8 задание
|
||||
|
||||
select o.id, o.order_date, p.name as product_name, oi.quantity, oi.price_at_purchase from orders o
|
||||
join order_items oi on o.id = oi.order_id
|
||||
join products p on oi.product_id = p.id
|
||||
where o.user_id in (select id from users where name = 'Alice');
|
||||
|
||||
-- 9 задание
|
||||
|
||||
select o.id as order_id, o.user_id, o.status from orders o
|
||||
left join order_items oi on o.id = oi.order_id
|
||||
where oi.product_id is null; -- таких у нас заказов нет, во всех заказах есть товары.
|
||||
|
||||
--------------------------------------------------------------------------------------------
|
||||
-- UNION
|
||||
-- 1 задание
|
||||
select id, name, is_active from users
|
||||
where is_active is false
|
||||
union
|
||||
select id, name, is_active from users
|
||||
where is_active is true
|
||||
order by name;
|
||||
|
||||
-- 2 задание
|
||||
select id as order_id, user_id, order_date,
|
||||
case when o.order_date < '2025-02-01' then 'old' else 'new' end as period
|
||||
from orders o;
|
||||
-- 3е задание не имеет смысла, т.к. все заказы покупались, там нечего соединять
|
||||
|
||||
----------------------------------------------------------------------------------------------
|
||||
-- Agregation
|
||||
-- 1 задание
|
||||
select category, COUNT(*) as products_count from products
|
||||
group by category
|
||||
order by products_count desc;
|
||||
|
||||
-- 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;
|
||||
|
||||
-- 3 задание
|
||||
select p.category, SUM(oi.quantity * oi.price_at_purchase) as category_revenue from products p
|
||||
join order_items oi on oi.product_id = p.id
|
||||
group by p.category
|
||||
order by category_revenue desc;
|
||||
|
||||
-- 4 задание
|
||||
select order_id, SUM(quantity * price_at_purchase) as order_revenue from order_items oi
|
||||
join orders o on oi.order_id = o.id
|
||||
where o.status = 'paid'
|
||||
group by oi.order_id
|
||||
order by order_revenue desc;
|
||||
|
||||
-- 5 задание
|
||||
select p.category, SUM(oi.quantity * oi.price_at_purchase) as category_revenue from products p
|
||||
join order_items oi on oi.product_id = p.id
|
||||
group by p.category
|
||||
having SUM(oi.quantity * oi.price_at_purchase) > 1000
|
||||
order by category_revenue desc;
|
||||
|
||||
-- 6 задание
|
||||
select country, COUNT(*) as active_users_count
|
||||
from users
|
||||
where is_active is true
|
||||
group by country
|
||||
having COUNT(*) >= 2
|
||||
order by active_users_count desc;
|
||||
|
||||
-- 7 задание
|
||||
select p.name, SUM(oi.quantity) as total_quantity_sold from products p
|
||||
join order_items oi on oi.product_id = p.id
|
||||
group by p.name
|
||||
order by total_quantity_sold desc
|
||||
limit 3;
|
||||
|
||||
-- 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) < 10000 -- сделал меньше 10000 потому что заказов дешевле 100 нет.
|
||||
order by order_revenue;
|
||||
|
||||
--------------------------------------------------------------------------------------------------------------
|
||||
--Functions:date strings logic
|
||||
-- 1 задание
|
||||
select name,
|
||||
created_at::date as created_date,
|
||||
CURRENT_DATE - created_at::date as days_since_registration
|
||||
from users
|
||||
where CURRENT_DATE - created_at::date > 750
|
||||
order by days_since_registration desc;
|
||||
|
||||
-- 2 задание
|
||||
select name, LOWER(email) as email_clean,
|
||||
substring(LOWER(email) from position('@' in email) + 1) as domain
|
||||
from users
|
||||
where email is not null
|
||||
order by domain, name;
|
||||
|
||||
-- 3 задание
|
||||
select name, age,
|
||||
case when age < 25 then 'young'
|
||||
when age between 20 and 30 then 'adult'
|
||||
else 'senior'
|
||||
end as age_group
|
||||
from users
|
||||
order by age;
|
||||
|
||||
-- 4 задание
|
||||
with CTE as
|
||||
(select name, created_at::date,
|
||||
current_date - created_at::date as days_since_registration,
|
||||
case when is_active = true then 'hot'
|
||||
when current_date - created_at::date < 30 then 'hot'
|
||||
else 'regular'
|
||||
end as hot_flag
|
||||
from users)
|
||||
select * from CTE
|
||||
where hot_flag = 'hot';
|
||||
|
||||
-- 5 задание
|
||||
with CTE as
|
||||
(select count(id) as total_users,
|
||||
COUNT(email) as with_email,
|
||||
(select count(*) from users where email is null) as without_email
|
||||
from users)
|
||||
select total_users, with_email, without_email,
|
||||
ROUND(100.0 * without_email / total_users, 2) as percentage_no_email
|
||||
from CTE;
|
||||
|
||||
-- 6 задание
|
||||
select name,
|
||||
CURRENT_DATE - created_at::date as days_since_registration,
|
||||
case
|
||||
when CURRENT_DATE - created_at::date <= 720 then 'new'
|
||||
when CURRENT_DATE - created_at::date BETWEEN 721 and 750 then 'middle'
|
||||
else 'old'
|
||||
end as tenure_group
|
||||
from users
|
||||
order by days_since_registration;
|
||||
|
||||
----------------------------------------------------------------------------------------------------
|
||||
--Subquery/CTE
|
||||
-- 1 задание
|
||||
select name
|
||||
from users
|
||||
where id in (select distinct user_id from orders)
|
||||
order by name;
|
||||
|
||||
-- 2 задание
|
||||
select id, name, email
|
||||
from users u
|
||||
where not exists (
|
||||
select user_id
|
||||
from orders o
|
||||
where o.user_id = u.id)
|
||||
|
||||
-- 3 задание
|
||||
select name,
|
||||
(select COUNT(*) orders_count from orders o
|
||||
where o.user_id = u.id)
|
||||
from users u
|
||||
order by orders_count desc, name;
|
||||
|
||||
-- 4 задание
|
||||
with CTE as (
|
||||
select user_id, SUM(quantity * price_at_purchase) as total_revenue
|
||||
from orders o
|
||||
join order_items oi on o.id = oi.order_id
|
||||
group by user_id
|
||||
)
|
||||
select u.name, c.total_revenue from users u
|
||||
join CTE c on u.id = c.user_id
|
||||
order by c.total_revenue desc;
|
||||
|
||||
-- 5 задание
|
||||
with CTE as (
|
||||
select product_id, SUM(quantity * price_at_purchase) as product_revenue
|
||||
from order_items
|
||||
group by product_id
|
||||
)
|
||||
select p.name as product_name, p.category, c.product_revenue from CTE c
|
||||
join products p on c.product_id = p.id
|
||||
order by c.product_revenue desc
|
||||
limit 3;
|
||||
|
||||
-- 6 задание
|
||||
with CTE as (
|
||||
select o.user_id, SUM(quantity * price_at_purchase) as total_revenue from orders o
|
||||
join order_items oi on o.id = oi.order_id
|
||||
group by o.user_id
|
||||
)
|
||||
select u.name, u.email, c.total_revenue from users u
|
||||
join CTE c on u.id = c.user_id
|
||||
where u.is_active is true
|
||||
and c.total_revenue > 10000;
|
||||
|
||||
-- 7 задание
|
||||
|
||||
with CTE as (
|
||||
select order_id, SUM(quantity * price_at_purchase) as order_revenue
|
||||
from order_items oi
|
||||
join orders o on oi.order_id = o.id
|
||||
where o.status = 'paid'
|
||||
group by order_id
|
||||
)
|
||||
select * from CTE
|
||||
where order_revenue < 10000;
|
||||
|
||||
---------------------------------------------------------------------------------------------
|
||||
--WINDOW FUNCTIONS
|
||||
-- 1 задание
|
||||
select u.id as user_id, u.name, o.id as order_id, o.order_date,
|
||||
row_number() over (partition by o.user_id order by o.order_date) as order_number_for_user
|
||||
from users u
|
||||
join orders o on u.id = o.user_id;
|
||||
|
||||
-- 2 задание
|
||||
with CTE as (
|
||||
select u.id as user_id, u.name as user_name, order_id, o.order_date, SUM(quantity * price_at_purchase) as order_revenue
|
||||
from order_items oi
|
||||
join orders o on oi.order_id = o.id
|
||||
join users u on o.user_id = u.id
|
||||
group by u.id, u.name, order_id, o.order_date
|
||||
order by user_id
|
||||
)
|
||||
select user_id, user_name, order_id, order_date, order_revenue,
|
||||
SUM(order_revenue) over (partition by user_id order by order_date) as running_revenue_for_user
|
||||
from CTE
|
||||
|
||||
-- 3 задание
|
||||
with CTE as (
|
||||
select u.id as user_id, u.name as user_name, SUM(quantity * price_at_purchase) as total_revenue
|
||||
from order_items oi
|
||||
join orders o on oi.order_id = o.id
|
||||
join users u on o.user_id = u.id
|
||||
group by u.id, u.name
|
||||
)
|
||||
select user_name, total_revenue,
|
||||
RANK() over (order by total_revenue desc) as revenue_rank,
|
||||
dense_rank() over (order by total_revenue desc) as dense_revenue_rank
|
||||
from CTE;
|
||||
|
||||
|
||||
-- 4 задание
|
||||
select u.name, o.id as order_id, order_date,
|
||||
first_value(o.order_date) over (partition by user_id order by order_date) as first_order_date,
|
||||
last_value(o.order_date) over (partition by user_id order by order_date ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) as last_order_date
|
||||
from orders o
|
||||
join users u on u.id = o.user_id;
|
||||
|
||||
|
||||
-- 5 задание
|
||||
select u.name as user_name, o.id as order_id,
|
||||
COUNT(*) over (partition by u.id) as orders_per_user
|
||||
from users u
|
||||
join orders o on u.id = o.user_id;
|
||||
|
||||
-- 6 задание
|
||||
with CTE as (
|
||||
select u.id as user_id, u.name as user_name, order_id, o.order_date as order_date,
|
||||
SUM(quantity * price_at_purchase) as order_revenue
|
||||
from order_items oi
|
||||
join orders o on oi.order_id = o.id
|
||||
join users u on o.user_id = u.id
|
||||
group by u.id, u.name, order_id, o.order_date
|
||||
order by user_id
|
||||
)
|
||||
select user_name, order_id, order_date, order_revenue,
|
||||
LAG(order_revenue) over (partition by user_id order by order_date) as prev_order_revenue
|
||||
from CTE;
|
||||
|
||||
-- 7 задание
|
||||
with CTEa as (
|
||||
select product_id,
|
||||
o.order_date::date as order_date,
|
||||
SUM(quantity * price_at_purchase) as daily_category_revenue
|
||||
from order_items oi
|
||||
join orders o on oi.order_id = o.id
|
||||
group by product_id, order_date
|
||||
order by oi.product_id
|
||||
),
|
||||
CTEb as (
|
||||
select p.category, order_date, daily_category_revenue
|
||||
from CTEa a
|
||||
join products p on a.product_id = p.id
|
||||
)
|
||||
select category, order_date, daily_category_revenue,
|
||||
SUM(daily_category_revenue) over (partition by category order by order_date) as running_category_revenue
|
||||
from CTEb;
|
||||
|
||||
-----------------------------------------------------------------------------------------------------------
|
||||
-- VIEW and MATERIALIZED VIEW
|
||||
-- 1 задание
|
||||
create MATERIALIZED view mv_category_revenue
|
||||
as
|
||||
select p.category, SUM(quantity * price_at_purchase) as total_revenue
|
||||
from products p
|
||||
join order_items oi on oi.product_id = p.id
|
||||
join orders o on oi.order_id = o.id and o.status = 'paid'
|
||||
group by p.category
|
||||
order by total_revenue desc
|
||||
;
|
||||
|
||||
-- 2 задание
|
||||
create materialized view
|
||||
as
|
||||
select u.id, u.name, COUNT(o.id) as order_count
|
||||
from users u
|
||||
join orders o on u.id = o.user_id and o.status = 'paid'
|
||||
group by u.id, u.name
|
||||
order by order_count desc
|
||||
;
|
||||
|
||||
-- 3 задание
|
||||
create materialized view mv_daily_revenue
|
||||
as
|
||||
select order_date::date as sales_date, SUM(quantity * price_at_purchase) as daily_revenue from orders o
|
||||
join order_items oi on o.id = oi.order_id
|
||||
where o.status = 'paid'
|
||||
group by sales_date
|
||||
order by sales_date
|
||||
;
|
||||
|
||||
-- 4 задание
|
||||
refresh materialized view mv_daily_revenue;
|
||||
|
||||
-- В 1 случае витрину можно обновлять 1 раз в день в 10:00 или 2 раза в день в 10:00 и в 22:00
|
||||
-- Во 2 случае витрину нужно обновлять несколько раз в день, думаю каждые часа 2-3 то есть в 8 в 10 в 12 и тд.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user