Пэт проект по SQL

This commit is contained in:
elena belykh
2026-01-23 21:49:18 +03:00
parent 2eac702d46
commit d32a9cb0a3
@@ -0,0 +1,233 @@
CREATE TABLE users (
id INT PRIMARY KEY,
name TEXT,
age INT,
email TEXT,
registration_date DATE
);
INSERT INTO users 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');
SELECT * FROM users ORDER BY id;
CREATE TABLE courses (
id INT PRIMARY KEY,
title TEXT,
category TEXT,
created_at DATE
);
INSERT INTO courses VALUES
(1, 'SQL для начинающих', 'data', '2023-01-01'),
(2, 'Python для анализа данных', 'programming', '2023-01-15'),
(3, 'BI с нуля', 'business', '2023-03-01');
SELECT * FROM courses ORDER BY id;
CREATE TABLE lessons (
id INT PRIMARY KEY,
course_id INT,
title TEXT,
duration_min INT,
FOREIGN KEY (course_id) REFERENCES courses(id)
);
INSERT INTO lessons VALUES
(1, 1, 'SELECT и FROM', 10),
(2, 1, 'JOIN', 15),
(3, 2, 'Pandas', 20),
(4, 3, 'Основы BI', 12),
(5, 3, 'Метрики и дашборды', 18);
SELECT * FROM lessons ORDER BY id;
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 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');
SELECT * FROM enrollments ORDER BY id;
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 VALUES
(1, 1, 1, '2023-01-16 10:00:00'),
(2, 1, 2, '2023-01-16 10:15:00'),
(3, 2, 1, '2023-01-21 09:00:00'),
(4, 3, 3, '2023-03-06 12:00:00'),
(5, 4, 4, '2023-04-02 10:00:00'),
(6, 4, 5, '2023-04-03 10:00:00');
SELECT * FROM lesson_views ORDER BY id;
--Создаем materialized view c названием user_activity_summary
DROP MATERIALIZED VIEW IF EXISTS user_activity_summary;
CREATE MATERIALIZED VIEW user_activity_summary AS
WITH
enr AS (
SELECT
user_id,
COUNT(*) AS enrollment_count
FROM enrollments
GROUP BY user_id
),
views AS (
SELECT
user_id,
COUNT(DISTINCT lesson_id) AS viewed_lessons_count,
MIN(viewed_at) AS first_view,
MAX(viewed_at) AS last_view
FROM lesson_views
GROUP BY user_id
),
possible AS (
SELECT
e.user_id,
COUNT(l.id) AS possible_lessons
FROM enrollments e
JOIN lessons l ON l.course_id = e.course_id
GROUP BY e.user_id
)
SELECT
u.id AS user_id,
u.name,
enr.enrollment_count,
COALESCE(views.viewed_lessons_count, 0) AS viewed_lessons_count,
views.last_view,
views.first_view,
ROUND(
COALESCE(views.viewed_lessons_count, 0)::numeric
/ possible.possible_lessons * 100,
2
) || '%' AS engagement_rate
FROM users u
JOIN enr ON enr.user_id = u.id
JOIN possible ON possible.user_id = u.id
LEFT JOIN views ON views.user_id = u.id
ORDER BY u.id;
--Проверка
SELECT * FROM user_activity_summary ORDER BY user_id;
--Создаем materialized view c названием course_summary
DROP MATERIALIZED VIEW IF EXISTS course_summary;
CREATE MATERIALIZED VIEW course_summary AS
WITH
-- 1) сколько уроков в каждом курсе
lessons_cnt AS (
SELECT
course_id,
COUNT(*) AS lessons_count
FROM lessons
GROUP BY course_id
),
-- 2) сколько уникальных пользователей записано на курс
users_cnt AS (
SELECT
course_id,
COUNT(DISTINCT user_id) AS unique_users
FROM enrollments
GROUP BY course_id
),
-- 3) просмотры по курсу (через lessons -> course_id)
views_cnt 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 lessons l
LEFT JOIN lesson_views lv ON lv.lesson_id = l.id
GROUP BY l.course_id
)
SELECT
c.id AS course_id,
c.title AS course_title,
COALESCE(u.unique_users, 0) AS unique_users,
COALESCE(ls.lessons_count, 0) AS lessons_count,
COALESCE(v.total_views, 0) AS total_views,
ROUND(
COALESCE(v.total_views, 0)::numeric / NULLIF(COALESCE(u.unique_users, 0), 0),
2
) AS avg_views_per_user,
v.first_viewed_at,
v.last_viewed_at
FROM courses c
LEFT JOIN users_cnt u ON u.course_id = c.id
LEFT JOIN lessons_cnt ls ON ls.course_id = c.id
LEFT JOIN views_cnt v ON v.course_id = c.id
ORDER BY c.id;
SELECT * FROM course_summary ORDER BY course_id;
--Создаем materialized view c названием platform_summary
DROP MATERIALIZED VIEW IF EXISTS platform_summary;
CREATE MATERIALIZED VIEW platform_summary AS
SELECT
(SELECT COUNT(*) FROM users) AS total_users,
(SELECT COUNT(*) FROM courses) AS total_courses,
(SELECT COUNT(*) FROM lessons) AS total_lessons,
(SELECT COUNT(DISTINCT user_id) FROM lesson_views) AS users_with_views,
ROUND(
(SELECT COUNT(*) FROM lessons)::numeric
/ (SELECT COUNT(*) FROM courses),
2
) AS avg_lessons_per_course,
ROUND(
(SELECT COUNT(*) FROM lesson_views)::numeric
/ (SELECT COUNT(*) FROM lessons),
2
) AS avg_views_per_lesson;
SELECT * FROM platform_summary;
--Доп. задание: EXPLAIN
EXPLAIN SELECT * FROM user_activity_summary;
EXPLAIN SELECT * FROM course_summary;