Merge branch 'main' into OS-412

This commit is contained in:
2026-04-10 22:19:07 +04:00
19 changed files with 2178 additions and 0 deletions
+26
View File
@@ -0,0 +1,26 @@
CREATE MATERIALIZED VIEW platform_summary AS
with users_counts as (
select
COUNT(distinct u.id) as total_users,
COUNT(distinct lv.user_id) as users_with_views
from users u
left join lesson_views lv on lv.user_id = u.id
),
courses_lessons_count as (
select COUNT(distinct c.id) as total_courses,
COUNT(distinct l.id) as total_lessons
from courses c
left join lessons l on l.course_id = c.id
),
views_count as (
select COUNT(distinct lv.lesson_id) as lessons_with_views,
COUNT(distinct lv.id) as total_views
from lesson_views lv
)
select uc.total_users, clc.total_courses, clc.total_lessons, uc.users_with_views,
ROUND(1.00 * clc.total_lessons / nullif(clc.total_courses, 0), 2) as avg_lessons_per_course,
ROUND(1.00 * vc.total_views / nullif(clc.total_lessons, 0), 2) as avg_views_per_lesson
from users_counts uc
cross join courses_lessons_count clc
cross join views_count vc
;
+28
View File
@@ -0,0 +1,28 @@
CREATE MATERIALIZED VIEW users_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
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 case when user_id in (select user_id from enrollments) then user_id end) as enrolled_users,
COUNT(distinct case when user_id in (select user_id from lesson_views) then user_id end) 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
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::numeric / users_in_cohort as avg_courses_per_user,
avg_time_to_first_view
from CTE
;
+466
View File
@@ -0,0 +1,466 @@
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
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) as avg_views_per_user,
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-е задание сделал с помощью нейросети, потому что сам вообще никак к нему подобраться не мог.
-----------------------------------------------------------------------------------------------------------------
-- Доп. Задание №1 Анализ drop-off точек
select course_id, stage_name, users_count,
100 - conversion_from_previous as lost_precentage
from conversion_funnel
where stage_name = 'started'
order by lost_precentage desc
;
--------------------------------------------------------------------------------------------------------------------
-- Доп. Задание №2 Топ-3 урока с повторными просмотрами
select lesson_id
from lesson_popularity_ranking
where avg_views_per_user > 1
limit 3
;
---------------------------------------------------------------------------------------------------------------------
-- Доп. Задание №3 Лучшая когорта по retention
select cohort_month, retention_rate
from user_cohort_analysis
order by retention_rate desc
limit 2
;
-- В нашем случае два месяца с одинаковыми лучшими показателями retention это 2023-01 и 2023-02. Это является следствием того, что у нас
-- наибольшее количество зарегистрированных пользователей именно в эти месяцы, а именно 2023-01 = 40%, а 2023-02 = 20%, соотвественно 60% пользователей были зарегистрированы в эти месяцы.
+525
View File
@@ -0,0 +1,525 @@
-----------------------------------------------------------
--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)
FOREIGN KEY (user_id) REFERENCES users(id)
);
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)
FOREIGN KEY ()
);
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 < 20 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 и тд.
Binary file not shown.

After

Width:  |  Height:  |  Size: 175 KiB

@@ -0,0 +1,72 @@
--Задача 1: Создай таблицу page_views
CREATE TABLE page_views (
user_id UInt64,
url String,
view_time DateTime
)
ENGINE = MergeTree()
PARTITION BY toYYYYMM(view_time)
ORDER BY (user_id, view_time);
--Задача 2: Создай таблицу users
CREATE TABLE users (
id UInt64,
name String,
updated_at DateTime
)
ENGINE = ReplacingMergeTree(updated_at)
ORDER BY id;
-- Задача 3: Создай таблицу region_sales
CREATE TABLE region_sales (
region String,
date Date,
sales UInt64
)
ENGINE = SummingMergeTree()
PARTITION BY toYYYYMM(date)
ORDER BY (region, date);
--Задача 4.1: Создай таблицу user_metrics
CREATE TABLE user_metrics (
region String,
avg_age_state AggregateFunction(avg, UInt8),
active_users_state AggregateFunction(uniq, UInt64)
)
ENGINE = AggregatingMergeTree()
ORDER BY region;
--Задача 4.3: - Вставь данные и Читай их через `avgMerge()` и `uniqMerge()`
INSERT INTO user_metrics
SELECT
region,
avgState(age) AS avg_age_state,
uniqState(toUInt64(user_id)) AS active_users_state
FROM
(
SELECT 'Samara' AS region, 25 AS age, 1 AS user_id
UNION ALL
SELECT 'Moscow', 30, 2
UNION ALL
SELECT 'Moscow', 22, 3
UNION ALL
SELECT 'Samara', 22, 4
UNION ALL
SELECT 'Sochi', 34, 5
)
GROUP BY region;
--Задача 4.4: - Читай их через `avgMerge()` и `uniqMerge()`
SELECT
region,
avgMerge(avg_age_state),
uniqMerge(active_users_state)
FROM user_metrics
GROUP BY region;
+105
View File
@@ -0,0 +1,105 @@
--Витрина dm.lesson_popularity_summary
CREATE MATERIALIZED VIEW dm.lesson_popularity_summary as
select
l.lesson_id,
l.title as lesson_title,
c.course_id,
c.title as course_title,
COUNT(f.user_id) as total_views,
COUNT(DISTINCT f.user_id) as unique_users,
MIN(f.viewed_at) as first_view,
MAX(f.viewed_at) as last_view
FROM core.fact_lesson_views f
JOIN core.dim_lesson l
ON f.lesson_id = l.lesson_id
JOIN core.dim_course c
ON l.course_id = c.course_id
GROUP BY
l.lesson_id,
l.title,
c.course_id,
c.title
order by lesson_id;
select * from dm.lesson_popularity_summary;
--Удалил лишний индекс
DROP INDEX core.idx_fact_views_course_id;
-- Все индексы для CORE-таблиц
SELECT
tablename,
indexname,
indexdef
FROM pg_indexes
WHERE schemaname = 'core'
AND tablename IN (
'dim_course',
'dim_date',
'dim_lesson',
'dim_user',
'enrollments',
'fact_lesson_views'
)
ORDER by indexname, tablename;
--Витрина dm.inactive_users_summary
CREATE MATERIALIZED VIEW dm.inactive_users_summary as
select
du.user_id,
du.name as user_name,
du.email,
du.age,
COUNT(e.course_id) as enrollments_count,
du.registration_date
from core.dim_user du
left join core.enrollments e
on du.user_id = e.user_id
left join core.fact_lesson_views flv
on du.user_id = flv.user_id
where flv.user_id is NULL
group by
du.user_id,
du.name,
du.email,
du.age,
du.registration_date
order by du.user_id;
select * from dm.inactive_users_summary;
--Витрина dm.course_completion_rate
CREATE MATERIALIZED VIEW dm.course_completion_rate as
select
du.user_id,
du.name as user_name,
dc.course_id,
dc.title as course_title,
COUNT(DISTINCT dl.lesson_id) AS lessons_in_course,
COUNT(DISTINCT flv.lesson_id) AS lessons_viewed,
ROUND(COUNT(DISTINCT flv.lesson_id)::numeric / NULLIF(COUNT(DISTINCT dl.lesson_id), 0), 2) AS completion_rate
from core.enrollments e
left join core.dim_user du
on du.user_id = e.user_id
left join core.dim_course dc
on dc.course_id = e.course_id
left join core.dim_lesson dl
on dl.course_id = e.course_id
left join core.fact_lesson_views flv
on flv.user_id = e.user_id
and flv.lesson_id = dl.lesson_id
group by
du.user_id,
du.name,
dc.course_id,
dc.title
order by du.user_id;
select * from dm.course_completion_rate order by user_id;
--Этап 5. Проверка
SELECT * FROM dm.lesson_popularity_summary LIMIT 10;
SELECT * FROM dm.inactive_users_summary LIMIT 10;
SELECT * FROM dm.course_completion_rate LIMIT 10;
--Все витрины отображаются корректно. Скрины: "название витрины".png
Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 104 KiB

@@ -0,0 +1,508 @@
--
-- PostgreSQL database dump
--
-- Dumped from database version 9.4.26
-- Dumped by pg_dump version 17.5
-- Started on 2026-01-17 22:42:00
SET statement_timeout = 0;
SET lock_timeout = 0;
SET idle_in_transaction_session_timeout = 0;
SET transaction_timeout = 0;
SET client_encoding = 'UTF8';
SET standard_conforming_strings = on;
SELECT pg_catalog.set_config('search_path', '', false);
SET check_function_bodies = false;
SET xmloption = content;
SET client_min_messages = warning;
SET row_security = off;
--
-- TOC entry 10 (class 2615 OID 25610)
-- Name: core; Type: SCHEMA; Schema: -; Owner: dsolovianov
--
CREATE SCHEMA core;
ALTER SCHEMA core OWNER TO dsolovianov;
--
-- TOC entry 11 (class 2615 OID 25611)
-- Name: dm; Type: SCHEMA; Schema: -; Owner: dsolovianov
--
CREATE SCHEMA dm;
ALTER SCHEMA dm OWNER TO dsolovianov;
--
-- TOC entry 9 (class 2615 OID 25609)
-- Name: raw; Type: SCHEMA; Schema: -; Owner: dsolovianov
--
CREATE SCHEMA raw;
ALTER SCHEMA raw OWNER TO dsolovianov;
SET default_tablespace = '';
--
-- TOC entry 273 (class 1259 OID 25635)
-- Name: dim_course; Type: TABLE; Schema: core; Owner: dsolovianov
--
CREATE TABLE core.dim_course (
course_id integer NOT NULL,
title text,
category text
);
ALTER TABLE core.dim_course OWNER TO dsolovianov;
--
-- TOC entry 275 (class 1259 OID 25656)
-- Name: dim_date; Type: TABLE; Schema: core; Owner: dsolovianov
--
CREATE TABLE core.dim_date (
date date NOT NULL,
year integer,
month integer,
day integer,
weekday text
);
ALTER TABLE core.dim_date OWNER TO dsolovianov;
--
-- TOC entry 274 (class 1259 OID 25643)
-- Name: dim_lesson; Type: TABLE; Schema: core; Owner: dsolovianov
--
CREATE TABLE core.dim_lesson (
lesson_id integer NOT NULL,
title text,
duration_min integer,
course_id integer
);
ALTER TABLE core.dim_lesson OWNER TO dsolovianov;
--
-- TOC entry 272 (class 1259 OID 25627)
-- Name: dim_user; Type: TABLE; Schema: core; Owner: dsolovianov
--
CREATE TABLE core.dim_user (
user_id integer NOT NULL,
name text,
age integer,
email text,
registration_date date
);
ALTER TABLE core.dim_user OWNER TO dsolovianov;
--
-- TOC entry 276 (class 1259 OID 25872)
-- Name: enrollments; Type: TABLE; Schema: core; Owner: dsolovianov
--
CREATE TABLE core.enrollments (
user_id integer,
course_id integer,
enrolled_at timestamp without time zone
);
ALTER TABLE core.enrollments OWNER TO dsolovianov;
--
-- TOC entry 277 (class 1259 OID 25885)
-- Name: fact_lesson_views; Type: TABLE; Schema: core; Owner: dsolovianov
--
CREATE TABLE core.fact_lesson_views (
user_id integer,
lesson_id integer,
course_id integer,
viewed_at timestamp without time zone
);
ALTER TABLE core.fact_lesson_views OWNER TO dsolovianov;
--
-- TOC entry 268 (class 1259 OID 25615)
-- Name: courses; Type: TABLE; Schema: raw; Owner: dsolovianov
--
CREATE TABLE raw.courses (
id integer,
title character varying(50),
category character varying(50),
created_at character varying(50)
);
ALTER TABLE raw.courses OWNER TO dsolovianov;
--
-- TOC entry 270 (class 1259 OID 25621)
-- Name: enrollments; Type: TABLE; Schema: raw; Owner: dsolovianov
--
CREATE TABLE raw.enrollments (
id integer,
user_id integer,
course_id integer,
enrolled_at character varying(50)
);
ALTER TABLE raw.enrollments OWNER TO dsolovianov;
--
-- TOC entry 271 (class 1259 OID 25624)
-- Name: lesson_views; Type: TABLE; Schema: raw; Owner: dsolovianov
--
CREATE TABLE raw.lesson_views (
id integer,
user_id integer,
lesson_id integer,
viewed_at character varying(50)
);
ALTER TABLE raw.lesson_views OWNER TO dsolovianov;
--
-- TOC entry 269 (class 1259 OID 25618)
-- Name: lessons; Type: TABLE; Schema: raw; Owner: dsolovianov
--
CREATE TABLE raw.lessons (
id integer,
course_id integer,
title character varying(50),
duration_min integer
);
ALTER TABLE raw.lessons OWNER TO dsolovianov;
--
-- TOC entry 267 (class 1259 OID 25612)
-- Name: users; Type: TABLE; Schema: raw; Owner: dsolovianov
--
CREATE TABLE raw.users (
id integer,
name character varying(50),
age integer,
email character varying(50),
registration_date character varying(50)
);
ALTER TABLE raw.users OWNER TO dsolovianov;
--
-- TOC entry 2506 (class 0 OID 25635)
-- Dependencies: 273
-- Data for Name: dim_course; Type: TABLE DATA; Schema: core; Owner: dsolovianov
--
COPY core.dim_course (course_id, title, category) FROM stdin;
2 Python для анализа данных programming
1 SQL для начинающих data
3 BI с нуля business
\.
--
-- TOC entry 2508 (class 0 OID 25656)
-- Dependencies: 275
-- Data for Name: dim_date; Type: TABLE DATA; Schema: core; Owner: dsolovianov
--
COPY core.dim_date (date, year, month, day, weekday) FROM stdin;
2023-01-15 2023 1 15 Sunday
2023-01-16 2023 1 16 Monday
2023-01-21 2023 1 21 Saturday
2023-01-20 2023 1 20 Friday
2023-03-05 2023 3 5 Sunday
2023-02-01 2023 2 1 Wednesday
2023-04-02 2023 4 2 Sunday
2023-03-06 2023 3 6 Monday
2023-04-01 2023 4 1 Saturday
2023-04-03 2023 4 3 Monday
\.
--
-- TOC entry 2507 (class 0 OID 25643)
-- Dependencies: 274
-- Data for Name: dim_lesson; Type: TABLE DATA; Schema: core; Owner: dsolovianov
--
COPY core.dim_lesson (lesson_id, title, duration_min, course_id) FROM stdin;
4 Основы BI 12 3
5 Метрики и дашборды 18 3
2 JOIN 15 1
1 SELECT и FROM 10 1
3 Pandas 20 2
\.
--
-- TOC entry 2505 (class 0 OID 25627)
-- Dependencies: 272
-- Data for Name: dim_user; Type: TABLE DATA; Schema: core; Owner: dsolovianov
--
COPY core.dim_user (user_id, name, age, email, registration_date) FROM stdin;
3 Charlie 22 charlie@mail.com 2023-02-20
1 Alice 25 alice@mail.com 2023-01-10
2 Bob 30 bob@gmail.com 2023-02-05
5 Ethan 35 ethan@gmail.com 2023-03-10
4 Diana 28 diana@mail.com 2023-03-01
\.
--
-- TOC entry 2509 (class 0 OID 25872)
-- Dependencies: 276
-- Data for Name: enrollments; Type: TABLE DATA; Schema: core; Owner: dsolovianov
--
COPY core.enrollments (user_id, course_id, enrolled_at) FROM stdin;
4 3 2023-04-01 00:00:00
1 2 2023-02-01 00:00:00
2 1 2023-01-20 00:00:00
1 1 2023-01-15 00:00:00
3 2 2023-03-05 00:00:00
\.
--
-- TOC entry 2510 (class 0 OID 25885)
-- Dependencies: 277
-- Data for Name: fact_lesson_views; Type: TABLE DATA; Schema: core; Owner: dsolovianov
--
COPY core.fact_lesson_views (user_id, lesson_id, course_id, viewed_at) FROM stdin;
2 1 1 2023-01-21 09:00:00
1 2 1 2023-01-16 10:15:00
3 3 2 2023-03-06 12:00:00
1 1 1 2023-01-16 10:00:00
4 4 3 2023-04-02 10:00:00
4 5 3 2023-04-03 10:00:00
\.
--
-- TOC entry 2501 (class 0 OID 25615)
-- Dependencies: 268
-- Data for Name: courses; Type: TABLE DATA; Schema: raw; Owner: dsolovianov
--
COPY raw.courses (id, title, category, created_at) FROM stdin;
3 BI с нуля business 2023-03-01
1 SQL для начинающих data 2023-01-01
2 Python для анализа данных programming 2023-01-15
\.
--
-- TOC entry 2503 (class 0 OID 25621)
-- Dependencies: 270
-- Data for Name: enrollments; Type: TABLE DATA; Schema: raw; Owner: dsolovianov
--
COPY raw.enrollments (id, user_id, course_id, enrolled_at) FROM stdin;
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
\.
--
-- TOC entry 2504 (class 0 OID 25624)
-- Dependencies: 271
-- Data for Name: lesson_views; Type: TABLE DATA; Schema: raw; Owner: dsolovianov
--
COPY raw.lesson_views (id, user_id, lesson_id, viewed_at) FROM stdin;
2 1 2 2023-01-16 10:15:00.000
1 1 1 2023-01-16 10:00:00.000
3 2 1 2023-01-21 09:00:00.000
5 4 4 2023-04-02 10:00:00.000
4 3 3 2023-03-06 12:00:00.000
6 4 5 2023-04-03 10:00:00.000
\.
--
-- TOC entry 2502 (class 0 OID 25618)
-- Dependencies: 269
-- Data for Name: lessons; Type: TABLE DATA; Schema: raw; Owner: dsolovianov
--
COPY raw.lessons (id, course_id, title, duration_min) FROM stdin;
1 1 SELECT и FROM 10
2 1 JOIN 15
3 2 Pandas 20
4 3 Основы BI 12
5 3 Метрики и дашборды 18
\.
--
-- TOC entry 2500 (class 0 OID 25612)
-- Dependencies: 267
-- Data for Name: users; Type: TABLE DATA; Schema: raw; Owner: dsolovianov
--
COPY raw.users (id, name, age, email, registration_date) FROM stdin;
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
5 Ethan 35 ethan@gmail.com 2023-03-10
4 Diana 28 diana@mail.com 2023-03-01
\.
--
-- TOC entry 2314 (class 2606 OID 25642)
-- Name: dim_course dim_course_pkey; Type: CONSTRAINT; Schema: core; Owner: dsolovianov
--
ALTER TABLE ONLY core.dim_course
ADD CONSTRAINT dim_course_pkey PRIMARY KEY (course_id);
--
-- TOC entry 2319 (class 2606 OID 25663)
-- Name: dim_date dim_date_pkey; Type: CONSTRAINT; Schema: core; Owner: dsolovianov
--
ALTER TABLE ONLY core.dim_date
ADD CONSTRAINT dim_date_pkey PRIMARY KEY (date);
--
-- TOC entry 2316 (class 2606 OID 25650)
-- Name: dim_lesson dim_lesson_pkey; Type: CONSTRAINT; Schema: core; Owner: dsolovianov
--
ALTER TABLE ONLY core.dim_lesson
ADD CONSTRAINT dim_lesson_pkey PRIMARY KEY (lesson_id);
--
-- TOC entry 2312 (class 2606 OID 25634)
-- Name: dim_user dim_user_pkey; Type: CONSTRAINT; Schema: core; Owner: dsolovianov
--
ALTER TABLE ONLY core.dim_user
ADD CONSTRAINT dim_user_pkey PRIMARY KEY (user_id);
--
-- TOC entry 2317 (class 1259 OID 25906)
-- Name: idx_dim_lesson_course_id; Type: INDEX; Schema: core; Owner: dsolovianov
--
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
/*
1) Создание INDEX на таблицы в CORE-слое
*/
CREATE INDEX idx_dim_lesson_course_id ON core.dim_lesson USING btree (course_id);
CREATE INDEX idx_enrollments_course_id ON core.enrollments USING btree (course_id);
CREATE INDEX idx_fact_views_course_id ON core.fact_lesson_views USING btree (course_id);
CREATE INDEX idx_fact_views_course_viewed_at ON core.fact_lesson_views USING btree (course_id, viewed_at);
CREATE INDEX idx_fact_views_lesson_id ON core.fact_lesson_views USING btree (lesson_id);
CREATE INDEX idx_fact_views_user_id ON core.fact_lesson_views USING btree (user_id);
CREATE INDEX idx_fact_views_user_viewed_at ON core.fact_lesson_views USING btree (user_id, viewed_at);
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
ALTER TABLE ONLY core.dim_lesson
ADD CONSTRAINT dim_lesson_course_id_fkey FOREIGN KEY (course_id) REFERENCES core.dim_course(course_id);
--
-- TOC entry 2327 (class 2606 OID 25880)
-- Name: enrollments enrollments_course_id_fkey; Type: FK CONSTRAINT; Schema: core; Owner: dsolovianov
--
ALTER TABLE ONLY core.enrollments
ADD CONSTRAINT enrollments_course_id_fkey FOREIGN KEY (course_id) REFERENCES core.dim_course(course_id);
--
-- TOC entry 2328 (class 2606 OID 25875)
-- Name: enrollments enrollments_user_id_fkey; Type: FK CONSTRAINT; Schema: core; Owner: dsolovianov
--
ALTER TABLE ONLY core.enrollments
ADD CONSTRAINT enrollments_user_id_fkey FOREIGN KEY (user_id) REFERENCES core.dim_user(user_id);
--
-- TOC entry 2329 (class 2606 OID 25898)
-- Name: fact_lesson_views fact_lesson_views_course_id_fkey; Type: FK CONSTRAINT; Schema: core; Owner: dsolovianov
--
ALTER TABLE ONLY core.fact_lesson_views
ADD CONSTRAINT fact_lesson_views_course_id_fkey FOREIGN KEY (course_id) REFERENCES core.dim_course(course_id);
--
-- TOC entry 2330 (class 2606 OID 25893)
-- Name: fact_lesson_views fact_lesson_views_lesson_id_fkey; Type: FK CONSTRAINT; Schema: core; Owner: dsolovianov
--
ALTER TABLE ONLY core.fact_lesson_views
ADD CONSTRAINT fact_lesson_views_lesson_id_fkey FOREIGN KEY (lesson_id) REFERENCES core.dim_lesson(lesson_id);
--
-- TOC entry 2331 (class 2606 OID 25888)
-- Name: fact_lesson_views fact_lesson_views_user_id_fkey; Type: FK CONSTRAINT; Schema: core; Owner: dsolovianov
--
ALTER TABLE ONLY core.fact_lesson_views
ADD CONSTRAINT fact_lesson_views_user_id_fkey FOREIGN KEY (user_id) REFERENCES core.dim_user(user_id);
-- Completed on 2026-01-17 22:42:02
--
-- PostgreSQL database dump complete
--
+417
View File
@@ -0,0 +1,417 @@
SET statement_timeout = 0;
SET lock_timeout = 0;
SET idle_in_transaction_session_timeout = 0;
SET transaction_timeout = 0;
SET client_encoding = 'UTF8';
SET standard_conforming_strings = on;
SELECT pg_catalog.set_config('search_path', '', false);
SET check_function_bodies = false;
SET xmloption = content;
SET client_min_messages = warning;
SET row_security = off;
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- ЭТАП 1
-- 1.1 - СОЗДАНИЕ СХЕМ
CREATE SCHEMA core;
ALTER SCHEMA core OWNER TO dsolovianov;
CREATE SCHEMA dm;
ALTER SCHEMA dm OWNER TO dsolovianov;
CREATE SCHEMA raw;
ALTER SCHEMA raw OWNER TO dsolovianov;
SET default_tablespace = '';
-- 1.2 - Создание raw-таблиц
CREATE TABLE raw.courses (
id integer,
title character varying(50),
category character varying(50),
created_at character varying(50)
);
ALTER TABLE raw.courses OWNER TO dsolovianov;
CREATE TABLE raw.enrollments (
id integer,
user_id integer,
course_id integer,
enrolled_at character varying(50)
);
ALTER TABLE raw.enrollments OWNER TO dsolovianov;
CREATE TABLE raw.lesson_views (
id integer,
user_id integer,
lesson_id integer,
viewed_at character varying(50)
);
ALTER TABLE raw.lesson_views OWNER TO dsolovianov;
CREATE TABLE raw.lessons (
id integer,
course_id integer,
title character varying(50),
duration_min integer
);
ALTER TABLE raw.lessons OWNER TO dsolovianov;
CREATE TABLE raw.users (
id integer,
name character varying(50),
age integer,
email character varying(50),
registration_date character varying(50)
);
ALTER TABLE raw.users OWNER TO dsolovianov;
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Этап 3. Слой Core
CREATE TABLE core.dim_course (
course_id integer NOT NULL,
title text,
category text
);
ALTER TABLE core.dim_course OWNER TO dsolovianov;
CREATE TABLE core.dim_date (
date date NOT NULL,
year integer,
month integer,
day integer,
weekday text
);
ALTER TABLE core.dim_date OWNER TO dsolovianov;
CREATE TABLE core.dim_lesson (
lesson_id integer NOT NULL,
title text,
duration_min integer,
course_id integer
);
ALTER TABLE core.dim_lesson OWNER TO dsolovianov;
CREATE TABLE core.dim_user (
user_id integer NOT NULL,
name text,
age integer,
email text,
registration_date date
);
ALTER TABLE core.dim_user OWNER TO dsolovianov;
CREATE TABLE core.enrollments (
user_id integer,
course_id integer,
enrolled_at timestamp without time zone
);
ALTER TABLE core.enrollments OWNER TO dsolovianov;
CREATE TABLE core.fact_lesson_views (
user_id integer,
lesson_id integer,
course_id integer,
viewed_at timestamp without time zone
);
ALTER TABLE core.fact_lesson_views OWNER TO dsolovianov;
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
COPY core.dim_course (course_id, title, category) FROM stdin;
2 Python для анализа данных programming
1 SQL для начинающих data
3 BI с нуля business
\.
COPY core.dim_date (date, year, month, day, weekday) FROM stdin;
2023-01-15 2023 1 15 Sunday
2023-01-16 2023 1 16 Monday
2023-01-21 2023 1 21 Saturday
2023-01-20 2023 1 20 Friday
2023-03-05 2023 3 5 Sunday
2023-02-01 2023 2 1 Wednesday
2023-04-02 2023 4 2 Sunday
2023-03-06 2023 3 6 Monday
2023-04-01 2023 4 1 Saturday
2023-04-03 2023 4 3 Monday
\.
--
-- TOC entry 2500 (class 0 OID 25643)
-- Dependencies: 274
-- Data for Name: dim_lesson; Type: TABLE DATA; Schema: core; Owner: dsolovianov
--
COPY core.dim_lesson (lesson_id, title, duration_min, course_id) FROM stdin;
4 Основы BI 12 3
5 Метрики и дашборды 18 3
2 JOIN 15 1
1 SELECT и FROM 10 1
3 Pandas 20 2
\.
--
-- TOC entry 2498 (class 0 OID 25627)
-- Dependencies: 272
-- Data for Name: dim_user; Type: TABLE DATA; Schema: core; Owner: dsolovianov
--
COPY core.dim_user (user_id, name, age, email, registration_date) FROM stdin;
3 Charlie 22 charlie@mail.com 2023-02-20
1 Alice 25 alice@mail.com 2023-01-10
2 Bob 30 bob@gmail.com 2023-02-05
5 Ethan 35 ethan@gmail.com 2023-03-10
4 Diana 28 diana@mail.com 2023-03-01
\.
--
-- TOC entry 2502 (class 0 OID 25872)
-- Dependencies: 276
-- Data for Name: enrollments; Type: TABLE DATA; Schema: core; Owner: dsolovianov
--
COPY core.enrollments (user_id, course_id, enrolled_at) FROM stdin;
4 3 2023-04-01 00:00:00
1 2 2023-02-01 00:00:00
2 1 2023-01-20 00:00:00
1 1 2023-01-15 00:00:00
3 2 2023-03-05 00:00:00
\.
--
-- TOC entry 2503 (class 0 OID 25885)
-- Dependencies: 277
-- Data for Name: fact_lesson_views; Type: TABLE DATA; Schema: core; Owner: dsolovianov
--
COPY core.fact_lesson_views (user_id, lesson_id, course_id, viewed_at) FROM stdin;
2 1 1 2023-01-21 09:00:00
1 2 1 2023-01-16 10:15:00
3 3 2 2023-03-06 12:00:00
1 1 1 2023-01-16 10:00:00
4 4 3 2023-04-02 10:00:00
4 5 3 2023-04-03 10:00:00
\.
--
-- TOC entry 2494 (class 0 OID 25615)
-- Dependencies: 268
-- Data for Name: courses; Type: TABLE DATA; Schema: raw; Owner: dsolovianov
--
COPY raw.courses (id, title, category, created_at) FROM stdin;
3 BI с нуля business 2023-03-01
1 SQL для начинающих data 2023-01-01
2 Python для анализа данных programming 2023-01-15
\.
--
-- TOC entry 2496 (class 0 OID 25621)
-- Dependencies: 270
-- Data for Name: enrollments; Type: TABLE DATA; Schema: raw; Owner: dsolovianov
--
COPY raw.enrollments (id, user_id, course_id, enrolled_at) FROM stdin;
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
\.
--
-- TOC entry 2497 (class 0 OID 25624)
-- Dependencies: 271
-- Data for Name: lesson_views; Type: TABLE DATA; Schema: raw; Owner: dsolovianov
--
COPY raw.lesson_views (id, user_id, lesson_id, viewed_at) FROM stdin;
2 1 2 2023-01-16 10:15:00.000
1 1 1 2023-01-16 10:00:00.000
3 2 1 2023-01-21 09:00:00.000
5 4 4 2023-04-02 10:00:00.000
4 3 3 2023-03-06 12:00:00.000
6 4 5 2023-04-03 10:00:00.000
\.
--
-- TOC entry 2495 (class 0 OID 25618)
-- Dependencies: 269
-- Data for Name: lessons; Type: TABLE DATA; Schema: raw; Owner: dsolovianov
--
COPY raw.lessons (id, course_id, title, duration_min) FROM stdin;
1 1 SELECT и FROM 10
2 1 JOIN 15
3 2 Pandas 20
4 3 Основы BI 12
5 3 Метрики и дашборды 18
\.
--
-- TOC entry 2493 (class 0 OID 25612)
-- Dependencies: 267
-- Data for Name: users; Type: TABLE DATA; Schema: raw; Owner: dsolovianov
--
COPY raw.users (id, name, age, email, registration_date) FROM stdin;
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
5 Ethan 35 ethan@gmail.com 2023-03-10
4 Diana 28 diana@mail.com 2023-03-01
\.
--
-- TOC entry 2314 (class 2606 OID 25642)
-- Name: dim_course dim_course_pkey; Type: CONSTRAINT; Schema: core; Owner: dsolovianov
--
ALTER TABLE ONLY core.dim_course
ADD CONSTRAINT dim_course_pkey PRIMARY KEY (course_id);
--
-- TOC entry 2318 (class 2606 OID 25663)
-- Name: dim_date dim_date_pkey; Type: CONSTRAINT; Schema: core; Owner: dsolovianov
--
ALTER TABLE ONLY core.dim_date
ADD CONSTRAINT dim_date_pkey PRIMARY KEY (date);
--
-- TOC entry 2316 (class 2606 OID 25650)
-- Name: dim_lesson dim_lesson_pkey; Type: CONSTRAINT; Schema: core; Owner: dsolovianov
--
ALTER TABLE ONLY core.dim_lesson
ADD CONSTRAINT dim_lesson_pkey PRIMARY KEY (lesson_id);
--
-- TOC entry 2312 (class 2606 OID 25634)
-- Name: dim_user dim_user_pkey; Type: CONSTRAINT; Schema: core; Owner: dsolovianov
--
ALTER TABLE ONLY core.dim_user
ADD CONSTRAINT dim_user_pkey PRIMARY KEY (user_id);
--
-- TOC entry 2319 (class 2606 OID 25651)
-- Name: dim_lesson dim_lesson_course_id_fkey; Type: FK CONSTRAINT; Schema: core; Owner: dsolovianov
--
ALTER TABLE ONLY core.dim_lesson
ADD CONSTRAINT dim_lesson_course_id_fkey FOREIGN KEY (course_id) REFERENCES core.dim_course(course_id);
--
-- TOC entry 2320 (class 2606 OID 25880)
-- Name: enrollments enrollments_course_id_fkey; Type: FK CONSTRAINT; Schema: core; Owner: dsolovianov
--
ALTER TABLE ONLY core.enrollments
ADD CONSTRAINT enrollments_course_id_fkey FOREIGN KEY (course_id) REFERENCES core.dim_course(course_id);
--
-- TOC entry 2321 (class 2606 OID 25875)
-- Name: enrollments enrollments_user_id_fkey; Type: FK CONSTRAINT; Schema: core; Owner: dsolovianov
--
ALTER TABLE ONLY core.enrollments
ADD CONSTRAINT enrollments_user_id_fkey FOREIGN KEY (user_id) REFERENCES core.dim_user(user_id);
--
-- TOC entry 2322 (class 2606 OID 25898)
-- Name: fact_lesson_views fact_lesson_views_course_id_fkey; Type: FK CONSTRAINT; Schema: core; Owner: dsolovianov
--
ALTER TABLE ONLY core.fact_lesson_views
ADD CONSTRAINT fact_lesson_views_course_id_fkey FOREIGN KEY (course_id) REFERENCES core.dim_course(course_id);
--
-- TOC entry 2323 (class 2606 OID 25893)
-- Name: fact_lesson_views fact_lesson_views_lesson_id_fkey; Type: FK CONSTRAINT; Schema: core; Owner: dsolovianov
--
ALTER TABLE ONLY core.fact_lesson_views
ADD CONSTRAINT fact_lesson_views_lesson_id_fkey FOREIGN KEY (lesson_id) REFERENCES core.dim_lesson(lesson_id);
--
-- TOC entry 2324 (class 2606 OID 25888)
-- Name: fact_lesson_views fact_lesson_views_user_id_fkey; Type: FK CONSTRAINT; Schema: core; Owner: dsolovianov
--
ALTER TABLE ONLY core.fact_lesson_views
ADD CONSTRAINT fact_lesson_views_user_id_fkey FOREIGN KEY (user_id) REFERENCES core.dim_user(user_id);
-- Completed on 2026-01-14 21:29:24
--
-- PostgreSQL database dump complete
--
@@ -0,0 +1,4 @@
"id","title","category","created_at"
1,SQL для начинающих,data,2023-01-01
2,Python для анализа данных,programming,2023-01-15
3,BI с нуля,business,2023-03-01
1 id title category created_at
2 1 SQL для начинающих data 2023-01-01
3 2 Python для анализа данных programming 2023-01-15
4 3 BI с нуля business 2023-03-01
@@ -0,0 +1,6 @@
"id","user_id","course_id","enrolled_at"
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
1 id user_id course_id enrolled_at
2 1 1 1 2023-01-15
3 2 1 2 2023-02-01
4 3 2 1 2023-01-20
5 4 3 2 2023-03-05
6 5 4 3 2023-04-01
@@ -0,0 +1,7 @@
"id","user_id","lesson_id","viewed_at"
1,1,1,2023-01-16 10:00:00.000
2,1,2,2023-01-16 10:15:00.000
3,2,1,2023-01-21 09:00:00.000
4,3,3,2023-03-06 12:00:00.000
5,4,4,2023-04-02 10:00:00.000
6,4,5,2023-04-03 10:00:00.000
1 id user_id lesson_id viewed_at
2 1 1 1 2023-01-16 10:00:00.000
3 2 1 2 2023-01-16 10:15:00.000
4 3 2 1 2023-01-21 09:00:00.000
5 4 3 3 2023-03-06 12:00:00.000
6 5 4 4 2023-04-02 10:00:00.000
7 6 4 5 2023-04-03 10:00:00.000
@@ -0,0 +1,6 @@
"id","course_id","title","duration_min"
1,1,SELECT и FROM,10
2,1,JOIN,15
3,2,Pandas,20
4,3,Основы BI,12
5,3,Метрики и дашборды,18
1 id course_id title duration_min
2 1 1 SELECT и FROM 10
3 2 1 JOIN 15
4 3 2 Pandas 20
5 4 3 Основы BI 12
6 5 3 Метрики и дашборды 18
@@ -0,0 +1,6 @@
"id","name","age","email","registration_date"
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
1 id name age email registration_date
2 1 Alice 25 alice@mail.com 2023-01-10
3 2 Bob 30 bob@gmail.com 2023-02-05
4 3 Charlie 22 charlie@mail.com 2023-02-20
5 4 Diana 28 diana@mail.com 2023-03-01
6 5 Ethan 35 ethan@gmail.com 2023-03-10
+1
View File
@@ -0,0 +1 @@
select * from users;
+1
View File
@@ -0,0 +1 @@
select * from users;