trading-platform-database/ddl/schemas/education/functions/08-views.sql

143 lines
4.9 KiB
SQL

-- =====================================================
-- VIEWS - Schema Education
-- =====================================================
-- Proyecto: OrbiQuant IA (Trading Platform)
-- Módulo: OQI-002 - Education
-- Especificación: ET-EDU-001-database.md
-- =====================================================
-- Vista: Cursos con estadísticas completas
CREATE OR REPLACE VIEW education.v_courses_with_stats AS
SELECT
c.*,
cat.name as category_name,
cat.slug as category_slug,
COUNT(DISTINCT m.id) as modules_count,
COUNT(DISTINCT l.id) as lessons_count,
SUM(l.video_duration_seconds) as total_duration_seconds,
COUNT(DISTINCT e.id) as enrollments_count,
COUNT(DISTINCT CASE WHEN e.status = 'completed' THEN e.id END) as completions_count
FROM education.courses c
LEFT JOIN education.categories cat ON c.category_id = cat.id
LEFT JOIN education.modules m ON c.id = m.course_id
LEFT JOIN education.lessons l ON m.id = l.module_id
LEFT JOIN education.enrollments e ON c.id = e.course_id
GROUP BY c.id, cat.name, cat.slug;
COMMENT ON VIEW education.v_courses_with_stats IS 'Cursos con estadísticas agregadas de módulos, lecciones y enrollments';
-- Vista: Progreso del usuario por curso
CREATE OR REPLACE VIEW education.v_user_course_progress AS
SELECT
e.user_id,
e.course_id,
c.title as course_title,
c.slug as course_slug,
c.thumbnail_url,
e.status as enrollment_status,
e.progress_percentage,
e.enrolled_at,
e.completed_at,
e.total_xp_earned,
COUNT(DISTINCT p.id) as lessons_viewed,
COUNT(DISTINCT CASE WHEN p.is_completed THEN p.id END) as lessons_completed
FROM education.enrollments e
JOIN education.courses c ON e.course_id = c.id
LEFT JOIN education.progress p ON e.id = p.enrollment_id
GROUP BY e.id, e.user_id, e.course_id, c.title, c.slug, c.thumbnail_url;
COMMENT ON VIEW education.v_user_course_progress IS 'Progreso detallado del usuario en cada curso enrollado';
-- Vista: Leaderboard de usuarios
CREATE OR REPLACE VIEW education.v_leaderboard_weekly AS
SELECT
ugp.user_id,
ugp.weekly_xp,
ugp.current_level,
ugp.current_streak_days,
RANK() OVER (ORDER BY ugp.weekly_xp DESC) as rank
FROM education.user_gamification_profile ugp
WHERE ugp.weekly_xp > 0
ORDER BY ugp.weekly_xp DESC
LIMIT 100;
COMMENT ON VIEW education.v_leaderboard_weekly IS 'Top 100 usuarios por XP semanal';
CREATE OR REPLACE VIEW education.v_leaderboard_monthly AS
SELECT
ugp.user_id,
ugp.monthly_xp,
ugp.current_level,
ugp.current_streak_days,
RANK() OVER (ORDER BY ugp.monthly_xp DESC) as rank
FROM education.user_gamification_profile ugp
WHERE ugp.monthly_xp > 0
ORDER BY ugp.monthly_xp DESC
LIMIT 100;
COMMENT ON VIEW education.v_leaderboard_monthly IS 'Top 100 usuarios por XP mensual';
CREATE OR REPLACE VIEW education.v_leaderboard_alltime AS
SELECT
ugp.user_id,
ugp.total_xp,
ugp.current_level,
ugp.total_courses_completed,
RANK() OVER (ORDER BY ugp.total_xp DESC) as rank
FROM education.user_gamification_profile ugp
WHERE ugp.total_xp > 0
ORDER BY ugp.total_xp DESC
LIMIT 100;
COMMENT ON VIEW education.v_leaderboard_alltime IS 'Top 100 usuarios por XP total histórico';
-- Vista: Estadísticas del usuario
CREATE OR REPLACE VIEW education.v_user_statistics AS
SELECT
ugp.user_id,
ugp.total_xp,
ugp.current_level,
ugp.xp_to_next_level,
ugp.current_streak_days,
ugp.longest_streak_days,
ugp.total_courses_completed,
ugp.total_lessons_completed,
ugp.total_quizzes_passed,
ugp.total_certificates_earned,
ugp.average_quiz_score,
COUNT(DISTINCT e.id) as total_enrollments,
COUNT(DISTINCT CASE WHEN e.status = 'active' THEN e.id END) as active_enrollments,
COUNT(DISTINCT ua.id) as total_achievements
FROM education.user_gamification_profile ugp
LEFT JOIN education.enrollments e ON ugp.user_id = e.user_id
LEFT JOIN education.user_achievements ua ON ugp.user_id = ua.user_id
GROUP BY ugp.user_id, ugp.total_xp, ugp.current_level, ugp.xp_to_next_level,
ugp.current_streak_days, ugp.longest_streak_days, ugp.total_courses_completed,
ugp.total_lessons_completed, ugp.total_quizzes_passed, ugp.total_certificates_earned,
ugp.average_quiz_score;
COMMENT ON VIEW education.v_user_statistics IS 'Estadísticas completas del usuario (gamificación + progreso)';
-- Vista: Cursos populares
CREATE OR REPLACE VIEW education.v_popular_courses AS
SELECT
c.id,
c.title,
c.slug,
c.thumbnail_url,
c.difficulty_level,
c.avg_rating,
c.total_reviews,
c.total_enrollments,
COUNT(DISTINCT e.id) as recent_enrollments_30d,
COUNT(DISTINCT CASE WHEN e.status = 'completed' THEN e.id END) as completions
FROM education.courses c
LEFT JOIN education.enrollments e ON c.id = e.course_id
AND e.enrolled_at >= NOW() - INTERVAL '30 days'
WHERE c.status = 'published'
GROUP BY c.id
ORDER BY recent_enrollments_30d DESC, c.avg_rating DESC
LIMIT 50;
COMMENT ON VIEW education.v_popular_courses IS 'Top 50 cursos más populares (enrollments últimos 30 días)';