CREATE SCHEMA raw; CREATE SCHEMA core; CREATE SCHEMA dm; CREATE TABLE raw.users ( id INT, name VARCHAR(255), age INT, email VARCHAR(255), registration_date DATE ); CREATE TABLE raw.courses ( id INT, title VARCHAR(255), category VARCHAR(255), created_at DATE ); CREATE TABLE raw.lessons ( id INT, course_id INT, title VARCHAR(255), duration_min INT ); CREATE TABLE raw.enrollments ( id INT, user_id INT, course_id INT, enrolled_at DATE ); CREATE TABLE raw.lesson_views ( id INT, user_id INT, lesson_id INT, viewed_at TIMESTAMP ); CREATE TABLE core.dim_user ( user_id INT PRIMARY KEY, name TEXT, age INT, email TEXT, registration_date DATE ); CREATE TABLE core.dim_course ( course_id INT PRIMARY KEY, title TEXT, category TEXT ); CREATE TABLE core.dim_lesson ( lesson_id INT PRIMARY KEY, title TEXT, duration_min INT, course_id INT REFERENCES core.dim_course(course_id) ); CREATE TABLE core.fact_lesson_views ( user_id INT REFERENCES core.dim_user(user_id), lesson_id INT REFERENCES core.dim_lesson(lesson_id), course_id INT REFERENCES core.dim_course(course_id), viewed_at TIMESTAMP ); CREATE TABLE core.enrollments ( user_id INT REFERENCES core.dim_user(user_id), course_id INT REFERENCES core.dim_course(course_id), enrolled_at TIMESTAMP ); INSERT INTO core.dim_user (user_id, name, age, email, registration_date) SELECT DISTINCT id::INT, name::TEXT, age::INT, email::TEXT, registration_date::DATE FROM raw.users; INSERT INTO core.dim_course (course_id, title, category) SELECT DISTINCT id::INT, title::TEXT, category::TEXT FROM raw.courses; INSERT INTO core.dim_lesson (lesson_id, title, duration_min, course_id) SELECT DISTINCT id::INT, title::TEXT, duration_min::INT, course_id::INT FROM raw.lessons; INSERT INTO core.fact_lesson_views (user_id, lesson_id, course_id, viewed_at) SELECT DISTINCT rw.user_id::INT, rw.lesson_id::INT, l.course_id::INT, rw.viewed_at::TIMESTAMP FROM raw.lesson_views rw JOIN raw.lessons l ON rw.lesson_id = l.id; INSERT INTO core.enrollments (user_id, course_id, enrolled_at) SELECT DISTINCT user_id::INT, course_id::INT, enrolled_at::DATE FROM raw.enrollments; CREATE MATERIALIZED VIEW dm.dm_lesson_popularity_summary AS SELECT dl.lesson_id, dl.title AS lesson_title, dc.course_id, dc.title AS course_title, COUNT(*) AS total_views, COUNT(DISTINCT flv.user_id) AS unique_users, MIN(flv.viewed_at) AS first_view, MAX(flv.viewed_at) AS last_view FROM core.dim_lesson dl JOIN core.dim_course dc ON dc.course_id = dl.course_id JOIN core.fact_lesson_views flv ON flv.lesson_id = dl.lesson_id GROUP BY dl.lesson_id, dl.title, dc.course_id, dc.title; /* Цель: Показать популярность каждого урока. Поля витрины: - lesson_id — идентификатор урока - lesson_title — название урока - course_id — идентификатор курса - course_title — название курса - total_views — общее число просмотров урока - unique_users — количество уникальных пользователей - first_view — дата первого просмотра - last_view — дата последнего просмотра */ CREATE MATERIALIZED VIEW dm.dm_inactive_users_summary AS SELECT du.user_id, du.name AS user_name, du.email, du.age, COUNT(DISTINCT e.course_id) AS enrollments_count, du.registration_date FROM core.dim_user du LEFT JOIN core.enrollments e ON e.user_id = du.user_id WHERE NOT EXISTS ( SELECT 1 FROM core.fact_lesson_views flv WHERE flv.user_id = du.user_id ) GROUP BY du.user_id, du.name, du.email, du.age, du.registration_date; /* Цель: Определить невовлечённых пользователей и потенциальный отток. Поля витрины: - user_id — идентификатор пользователя - user_name — имя - email — почта - age — возраст - enrollments_count — количество курсов - registration_date — дата регистрации */ CREATE MATERIALIZED VIEW dm.course_completion_rate AS SELECT du.user_id, du.name AS user_name, c.course_id, c.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) * 1.0 / NULLIF(COUNT(DISTINCT dl.lesson_id), 0), 2 ) AS completion_rate FROM core.dim_user du JOIN core.enrollments e ON du.user_id = e.user_id JOIN core.dim_course c ON e.course_id = c.course_id JOIN core.dim_lesson dl ON c.course_id = dl.course_id LEFT JOIN core.fact_lesson_views flv ON dl.lesson_id = flv.lesson_id AND flv.user_id = du.user_id GROUP BY du.user_id, du.name, c.course_id, c.title ORDER BY du.user_id, c.course_id; /* Цель: Анализировать, насколько пользователи проходят курсы до конца. Поля витрины: - user_id — идентификатор пользователя - user_name — имя пользователя - course_id — идентификатор курса - course_title — название курса - total_lessons — количество уроков в курсе - lessons_viewed — число просмотренных уроков - completion_rate — lessons_viewed / total_lessons */