Files
homework/aharlamcev/postgresql/Pet-projectsql.sql
T
2026-02-23 15:06:03 +03:00

446 lines
15 KiB
SQL
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
create table users (
id INT primary key,
name VARCHAR(50) NOT NULL,
age INT,
email VARCHAR(50) NOT NULL,
registration_date date
);
INSERT INTO users (id, name, age, email, registration_date)
VALUES
(1, 'Alice', 25, 'alice@mail.com', '2023-01-10'),
(2, 'Bob', 30, 'bob@gmail.com', '2023-02-05'),
(3, 'Charlie', 22, 'charlie@mail.com', '2023-02-20'),
(4, 'Diana', 28, 'diana@mail.com', '2023-03-01'),
(5, 'Ethan', 35, 'ethan@gmail.com', '2023-03-10'),
(6, 'Frank', 29, 'frank@mail.com', '2023-01-05'),
(7, 'Grace', 26, 'grace@gmail.com', '2023-01-12'),
(8, 'Henry', 32, 'henry@mail.com', '2023-01-20'),
(9, 'Iris', 24, 'iris@gmail.com', '2023-02-10'),
(10, 'Jack', 27, 'jack@mail.com', '2023-04-15'),
(11, 'Kelly', 23, 'kelly@gmail.com', '2023-04-20'),
(12, 'Leo', 31, 'leo@mail.com', '2023-01-15'),
(13, 'Mia', 26, 'mia@gmail.com', '2023-01-18'),
(14, 'Nina', 28, 'nina@mail.com', '2023-01-08'),
(15, 'Oscar', 33, 'oscar@gmail.com', '2023-01-10'),
(16, 'Paul', 29, 'paul@mail.com', '2023-02-15'),
(17, 'Quinn', 24, 'quinn@gmail.com', '2023-03-20'),
(18, 'Rita', 27, 'rita@mail.com', '2023-04-01'),
(19, 'Sam', 30, 'sam@gmail.com', '2023-04-10'),
(20, 'Tina', 25, 'tina@mail.com', '2023-04-18');
create table courses (
id INT primary key,
title VARCHAR(100),
category VARCHAR(50),
created_at date
);
INSERT INTO courses (id, title, category, created_at)
VALUES
(1, 'SQL для начинающих', 'data', '2023-01-01'),
(2, 'Python для анализа данных', 'programming', '2023-01-15'),
(3, 'BI с нуля', 'business', '2023-03-01'),
(4, 'Excel для аналитиков', 'business', '2023-02-01'),
(5, 'Основы машинного обучения', 'data', '2023-03-15');
create table lessons (
id INT primary key,
course_id INT,
title VARCHAR(100),
duration_min INT,
foreign key (course_id) references courses(id)
);
INSERT INTO lessons (id, course_id, title, duration_min)
VALUES
(1, 1, 'SELECT и FROM', 10),
(2, 1, 'JOIN', 15),
(3, 1, 'WHERE и фильтрация', 12),
(4, 1, 'Агрегации и GROUP BY', 18),
(5, 1, 'Подзапросы', 25),
(6, 2, 'Pandas основы', 20),
(7, 2, 'NumPy', 15),
(8, 2, 'Визуализация данных', 22),
(9, 3, 'Основы BI', 12),
(10, 3, 'Метрики и дашборды', 18),
(11, 3, 'Power BI введение', 20),
(12, 4, 'Формулы в Excel', 15),
(13, 4, 'Сводные таблицы', 18),
(14, 4, 'Графики и диаграммы', 14),
(15, 5, 'Введение в ML', 20),
(16, 5, 'Линейная регрессия', 30),
(17, 5, 'Классификация', 28),
(18, 5, 'Кластеризация', 25);
create table enrollments (
id INT primary key,
user_id INT,
course_id INT,
enrolled_at date,
foreign key (user_id) references users(id),
foreign key (course_id) references courses(id)
);
INSERT INTO enrollments (id, user_id, course_id, enrolled_at)
VALUES
(1, 1, 1, '2023-01-15'),
(2, 1, 2, '2023-02-01'),
(3, 2, 1, '2023-01-20'),
(4, 3, 2, '2023-03-05'),
(5, 4, 3, '2023-04-01'),
(6, 6, 1, '2023-01-06'),
(7, 6, 2, '2023-01-10'),
(8, 6, 4, '2023-02-05'),
(9, 7, 1, '2023-01-13'),
(10, 7, 3, '2023-03-10'),
(11, 8, 1, '2023-01-22'),
(12, 8, 2, '2023-01-22'),
(13, 8, 3, '2023-01-22'),
(14, 9, 4, '2023-02-12'),
(15, 10, 1, '2023-04-16'),
(16, 11, 2, '2023-04-21'),
(17, 12, 1, '2023-01-16'),
(18, 13, 2, '2023-01-19'),
(19, 13, 4, '2023-02-20'),
(20, 14, 1, '2023-01-09'),
(21, 14, 2, '2023-01-09'),
(22, 14, 3, '2023-01-09'),
(23, 14, 4, '2023-02-01'),
(24, 14, 5, '2023-03-20'),
(25, 15, 1, '2023-01-11'),
(26, 15, 3, '2023-03-05'),
(27, 16, 2, '2023-02-16'),
(28, 16, 4, '2023-02-16'),
(29, 17, 3, '2023-03-22'),
(30, 17, 5, '2023-03-25'),
(31, 18, 1, '2023-04-02'),
(32, 19, 1, '2023-04-11'),
(33, 19, 2, '2023-04-11'),
(34, 20, 2, '2023-04-19'),
(35, 5, 5, '2023-03-20'),
(36, 1, 4, '2023-02-10'),
(37, 2, 3, '2023-03-15'),
(38, 3, 1, '2023-02-25'),
(39, 4, 2, '2023-03-10'),
(40, 6, 3, '2023-03-08'),
(41, 7, 2, '2023-02-01'),
(42, 9, 1, '2023-02-15'),
(43, 12, 3, '2023-03-10'),
(44, 15, 2, '2023-02-01'),
(45, 18, 4, '2023-04-05');
create table lesson_views (
id INT primary key,
user_id INT,
lesson_id INT,
viewed_at timestamp,
foreign key (user_id) references users(id),
foreign key (lesson_id) references lessons(id)
);
INSERT INTO lesson_views (id, user_id, lesson_id, viewed_at)
VALUES
(1, 1, 1, '2023-01-16 10:00:00'),
(2, 1, 2, '2023-01-16 10:15:00'),
(3, 1, 3, '2023-01-17 09:00:00'),
(4, 1, 4, '2023-01-17 09:30:00'),
(5, 1, 4, '2023-01-17 11:00:00'),
(6, 1, 4, '2023-01-18 10:00:00'),
(7, 1, 6, '2023-02-02 14:00:00'),
(8, 1, 12, '2023-02-15 10:00:00'),
(9, 1, 13, '2023-02-15 10:30:00'),
(10, 2, 1, '2023-01-21 09:00:00'),
(11, 2, 9, '2023-03-16 10:00:00'),
(12, 2, 10, '2023-03-16 10:30:00'),
(13, 3, 6, '2023-03-06 12:00:00'),
(14, 3, 1, '2023-02-26 11:00:00'),
(15, 3, 2, '2023-02-26 11:20:00'),
(16, 4, 9, '2023-04-02 10:00:00'),
(17, 4, 10, '2023-04-03 10:00:00'),
(18, 4, 6, '2023-03-12 14:00:00'),
(19, 4, 7, '2023-03-13 09:00:00'),
(20, 5, 15, '2023-03-21 10:00:00'),
(21, 5, 16, '2023-03-22 11:00:00'),
(22, 6, 1, '2023-01-07 10:00:00'),
(23, 6, 2, '2023-01-07 10:15:00'),
(24, 6, 3, '2023-01-08 09:00:00'),
(25, 6, 4, '2023-01-08 09:30:00'),
(26, 6, 5, '2023-01-09 10:00:00'),
(27, 6, 6, '2023-01-11 14:00:00'),
(28, 6, 7, '2023-01-12 10:00:00'),
(29, 6, 8, '2023-01-13 11:00:00'),
(30, 6, 12, '2023-02-06 09:00:00'),
(31, 6, 13, '2023-02-06 09:30:00'),
(32, 6, 14, '2023-02-07 10:00:00'),
(33, 6, 9, '2023-03-09 11:00:00'),
(34, 7, 1, '2023-01-14 10:00:00'),
(35, 7, 2, '2023-01-14 10:20:00'),
(36, 7, 3, '2023-01-15 09:00:00'),
(37, 7, 9, '2023-03-11 14:00:00'),
(38, 7, 10, '2023-03-11 14:30:00'),
(39, 9, 12, '2023-02-13 10:00:00'),
(40, 9, 13, '2023-02-13 10:30:00'),
(41, 9, 1, '2023-02-16 11:00:00'),
(42, 12, 1, '2023-01-17 10:00:00'),
(43, 12, 2, '2023-01-17 10:20:00'),
(44, 12, 1, '2023-04-10 11:00:00'),
(45, 12, 3, '2023-04-10 11:30:00'),
(46, 12, 9, '2023-03-12 10:00:00'),
(47, 13, 6, '2023-01-20 14:00:00'),
(48, 13, 7, '2023-01-21 10:00:00'),
(49, 13, 12, '2023-02-21 09:00:00'),
(50, 14, 1, '2023-01-09 08:00:00'),
(51, 14, 2, '2023-01-09 08:15:00'),
(52, 14, 3, '2023-01-10 10:00:00'),
(53, 14, 4, '2023-01-10 10:30:00'),
(54, 14, 5, '2023-01-11 09:00:00'),
(55, 14, 6, '2023-01-10 14:00:00'),
(56, 14, 7, '2023-01-11 10:00:00'),
(57, 14, 8, '2023-01-12 11:00:00'),
(58, 14, 9, '2023-01-10 08:00:00');
---------------------------------------------------------
-- 1 задание Активные пользователи
create materialized view user_activity_summary AS
with enroll_count as (
select u.id as user_id, u.name as user_name,
COUNT(e.course_id) as enrollment_count
from users u
join enrollments e on u.id = e.user_id
group by u.id, u.name
),
viewed_count as (
select ec.user_id, ec.user_name, enrollment_count,
COUNT(distinct lv.lesson_id) as viewed_lessons_count,
MIN(lv.viewed_at) as first_view,
MAX(lv.viewed_at) as last_view
from enroll_count ec
left join lesson_views lv on ec.user_id = lv.user_id
group by ec.user_id, ec.user_name, enrollment_count
),
possible_lessons as (
select u.id as user_id, COUNT(l.id) as poss_lessons
from users u
left join enrollments e on u.id = e.user_id
left join lessons l on e.course_id = l.course_id
group by u.id
)
select vc.user_id, user_name, enrollment_count, viewed_lessons_count, first_view, last_view,
ROUND(100.0 * viewed_lessons_count / pl.poss_lessons, 2) as engagement_rate
from viewed_count vc
left join possible_lessons pl on vc.user_id = pl.user_id
;
------------------------------------------------------------------------------------------------------------------
-- 2 задание Эффективность курсов
create materialized view course_summary AS
with lessons_per_course as (
select c.id as course_id, c.title as course_title,
COUNT(distinct e.user_id) as unique_users,
COUNT(distinct l.id) as lessons_count
from courses c
left join enrollments e on c.id = e.course_id
join lessons l on e.course_id = l.course_id
group by c.id, c.title
),
course_views as (
select l.course_id,
COUNT(lv.id) as total_views,
MIN(lv.viewed_at) as first_viewed_at,
MAX(lv.viewed_at) as last_viewed_at
from lesson_views lv
join lessons l on lv.lesson_id = l.id
group by l.course_id
)
select lpc.course_id, lpc.course_title, lpc.unique_users, lpc.lessons_count,
ROUND(1.00 * cv.total_views / lpc.unique_users, 2) as avg_views_per_user,
cv.first_viewed_at,
cv.last_viewed_at
from lessons_per_course lpc
join course_views cv on lpc.course_id = cv.course_id
order by course_id
;
--------------------------------------------------------------------------------------------------
-- 3 задание Общая отчетность по взаимодействию
create materialized view platform_summary as
with total_counts as (
select COUNT(id) as total_users,
(select COUNT(id) from courses) as total_courses,
(select COUNT(id) from lessons) as total_lessons,
(select COUNT(id) from lesson_views) as total_views,
(select COUNT(distinct user_id) from lesson_views) as users_with_views
from users
)
SELECT total_users, total_courses, total_lessons, users_with_views,
ROUND(1.00 * total_lessons / total_courses, 2) as avg_lessons_per_course,
ROUND(1.00 * total_views / total_lessons, 2) as avg_views_per_lesson
from total_counts
;
-----------------------------------------------------------------------------------------------------
-- 4 Задание Когортный анализ пользователей
create materialized view user_cohort_analysis AS
with needed_users as (
select distinct u.id as user_id, u.registration_date as reg_date, e.course_id, lv.id as view_id,
lv.lesson_id as viewed_lesson_id,
FIRST_VALUE(lv.viewed_at) over (partition by lv.user_id order by lv.viewed_at) as first_view_date,
e.user_id as enrolled_users,
lv.user_id as active_users
from users u
left join enrollments e on u.id = e.user_id
left join lesson_views lv on e.user_id = lv.user_id
order by user_id
),
CTE as (
select
TO_CHAR(reg_date, 'YYYY-MM') as cohort_month,
COUNT(distinct user_id) as users_in_cohort,
COUNT(distinct enrolled_users) as enrolled_users,
COUNT(distinct active_users) as active_users,
COUNT(course_id) as courses_count,
extract('days' from AVG(first_view_date - reg_date)) as avg_time_to_first_view
from needed_users
where date_trunc('month', reg_date)::date = '2023-03-01'
group by cohort_month
)
select cohort_month, users_in_cohort, enrolled_users, active_users,
ROUND(100.0 * active_users / users_in_cohort, 2) as retention_rate,
courses_count / users_in_cohort as avg_courses_per_user,
avg_time_to_first_view
from CTE
;
------------------------------------------------------------------------------------------------------------------
-- 5 Задание Популярность курсов
create materialized view lesson_popularity_ranking as
with lessons_in_courses as (
select l.id as lesson_id, l.title as lesson_title, c.title as course_title,
COUNT(e.user_id) as enrolled_users
from lessons l
join courses c on l.course_id = c.id
join enrollments e on e.course_id = c.id
group by l.id, l.title, c.title
order by lesson_id
),
views_cte as (
select lic.lesson_id,
COUNT(lv.id) as total_views,
COUNT(distinct lv.user_id) as unique_viewers,
1.00 * COUNT(lv.id) / nullif(COUNT(distinct lv.user_id), 0) as avg_views_per_user,
COUNT(lic.enrolled_users) as enrolled_to_course
from lessons_in_courses lic
left join lesson_views lv on lic.lesson_id = lv.lesson_id
group by lic.lesson_id
)
select lic.lesson_id, lic.lesson_title, lic.course_title,
vc.total_views,
vc.unique_viewers,
coalesce(vc.avg_views_per_user, 0),
dense_rank() OVER (ORDER BY vc.total_views desc) as popularity_rank,
ROUND(100.0 * unique_viewers / enrolled_to_course, 2) as completion_rate
from lessons_in_courses lic
join views_cte vc on lic.lesson_id = vc.lesson_id
;
-----------------------------------------------------------------------------------------------
-- 6 Задания Воронка Конверсии
create materialized view conversion_funnel AS
with course_lessons as (
select c.id as course_id, c.title as course_title,
COUNT(l.id) as total_lessons
from courses c
join lessons l on l.course_id = c.id
group by c.id, c.title
),
registered_users as (
select COUNT(distinct id) as total_users
from users
),
enrolled_users as (
select e.course_id,
COUNT(distinct e.user_id) as enrolled_count
from enrollments e
group by e.course_id
),
started_users as (
select l.course_id,
COUNT(distinct lv.user_id) as started_count
from lessons l
join lesson_views lv on l.id = lv.lesson_id
group by l.course_id
),
user_progress as (
select l.course_id, lv.user_id,
COUNT(distinct lv.lesson_id) as viewed_lessons
from lesson_views lv
join lessons l on lv.lesson_id = l.id
group by l.course_id, lv.user_id
),
mid_progress_users as (
select up.course_id,
COUNT(distinct up.user_id) as mid_progress_count
from user_progress up
join course_lessons cl on up.course_id = cl.course_id
where up.viewed_lessons >= cl.total_lessons * 0.5
group by up.course_id
),
completed_users as (
select up.course_id,
COUNT(distinct up.user_id) as completed_count
from user_progress up
join course_lessons cl on up.course_id = cl.course_id
where up.viewed_lessons >= cl.total_lessons
group by up.course_id
),
funnel_stages as (
select cl.course_id, cl.course_title,
'registered' as stage_name,
ru.total_users as users_count,
1 as stage_order
from course_lessons cl
cross join registered_users ru
union all
select cl.course_id, cl.course_title,
'enrolled' as stage_name,
eu.enrolled_count as users_count,
2 as stage_order
from course_lessons cl
left join enrolled_users eu on cl.course_id = eu.course_id
union all
select cl.course_id, cl.course_title,
'started' as stage_name,
su.started_count as users_count,
3 as stage_order
from course_lessons cl
left join started_users su on cl.course_id = su.course_id
union all
select cl.course_id, cl.course_title,
'mid_progress' as stage_name,
coalesce(mpu.mid_progress_count, 0) as users_count,
4 as stage_order
from course_lessons cl
left join mid_progress_users mpu on cl.course_id = mpu.course_id
union all
select cl.course_id, cl.course_title,
'completed' as stage_name,
coalesce(cu.completed_count, 0) as users_count,
5 as stage_order
from course_lessons cl
left join completed_users cu on cl.course_id = cu.course_id
)
select course_id, course_title, stage_name, users_count,
ROUND(100.0 * users_count / NULLIF(LAG(users_count) over (partition by course_id order by stage_order), 0), 2)
as conversion_from_previous,
ROUND(100.0 * users_count / NULLIF(FIRST_VALUE(users_count) over (partition by course_id order by stage_order), 0), 2)
as conversion_from_start
from funnel_stages
;
-- Признаюсь 6-е задание сделал с помощью нейросети, потому что сам вообще никак к нему подобраться не мог.