CREATE MATERIALIZED VIEW user_cohort_analysis AS SELECT TO_CHAR(pu.cohort_month, 'YYYY-MM') AS MONTH, COUNT(DISTINCT pu.id) AS users_in_cohort, COUNT(DISTINCT pe.user_id) AS enrolled_users, COUNT(DISTINCT plv.user_id) AS active_users, ROUND(COUNT(DISTINCT plv.user_id) * 100.0 / COUNT(DISTINCT pu.id), 2) || '%' AS retention_rate, ROUND(AVG((SELECT COUNT(*) FROM pet_courses pc)) / COUNT(DISTINCT pu.id), 2) AS avg_courses_per_user, (SELECT ROUND(AVG(table_first_viewed_at.first_viewed_at::date - pu2.registration_date::date), 2) FROM pet_users pu2 LEFT JOIN ( SELECT plv2.user_id, MIN(plv2.viewed_at) AS first_viewed_at FROM pet_lesson_views plv2 GROUP BY plv2.user_id ) AS table_first_viewed_at ON pu2.id = table_first_viewed_at.user_id WHERE DATE_TRUNC('month', pu2.registration_date) = pu.cohort_month ) AS avg_time_to_first_view FROM ( SELECT *, DATE_TRUNC('month', registration_date) AS cohort_month FROM pet_users ) AS pu LEFT JOIN pet_enrollments pe ON pu.id = pe.user_id LEFT JOIN pet_lesson_views plv ON pu.id = plv.user_id GROUP BY pu.cohort_month ORDER BY pu.cohort_month;