【问渠哪得清如许】是我的一个系列,数据分析的内容,随着我的学习会陆续把我的笔记上传,如果你也正在学习相关内容,可以参考我的学习路径。
另外还有【问渠哪得清如许-产品经理】是阅读产品经理相关书籍的笔记。
【问渠哪得清如许-产品经理】阅读笔记《产品经理方法论------构建完整的产品知识体系(第2版)》上-CSDN博客
表名称和字段介绍

接着上次每天写完的题目

改正如下:
SELECT *
FROM (
SELECT sc.*,
ROW_NUMBER() OVER(PARTITION BY cid ORDER BY score DESC) AS rank_s
FROM sc
) t
WHERE rank_s < 4
ORDER BY cid, rank_s;
6、列出每个学生(sid和性别)的:上课总时长,数学上课总时长,理科上课总时长,男生上课总时长。
使用CASE WHEN + 聚合函数
SELECT
s.sid,
s.s_sex,
-- 上课总时长(分钟)
SUM(EXTRACT(EPOCH FROM (c.end_time - c.create_time))/60) AS total_minutes,
-- 数学上课总时长(课程编号02或课程名称包含数学)
SUM(CASE WHEN c.cid = '02' OR c.c_name LIKE '%数学%'
THEN EXTRACT(EPOCH FROM (c.end_time - c.create_time))/60
ELSE 0 END) AS math_minutes,
-- 理科上课总时长(物理、化学、生物等)
SUM(CASE WHEN c.c_type = '理科' OR c.c_name IN ('物理', '化学', '生物')
THEN EXTRACT(EPOCH FROM (c.end_time - c.create_time))/60
ELSE 0 END) AS science_minutes,
-- 男生上课总时长(学生性别为男生)
SUM(CASE WHEN s.s_sex = 'M'
THEN EXTRACT(EPOCH FROM (c.end_time - c.create_time))/60
ELSE 0 END) AS male_minutes
FROM stu s
LEFT JOIN cour_t ct ON s.sid = ct.sid
LEFT JOIN cour c ON ct.cid = c.cid
GROUP BY s.sid, s.s_sex
ORDER BY s.sid;
7、统计每门课程的学生选修人数(超过5人的才统计)。
使用GROUP BY + HAVING
SELECT
c.cid,
c.c_name,
COUNT(DISTINCT sc.sid) AS student_count
FROM cour c
LEFT JOIN sc ON c.cid = sc.cid
GROUP BY c.cid, c.c_name
HAVING COUNT(DISTINCT sc.sid) > 5
ORDER BY student_count DESC;
8、查询任何一门课程成绩在70分以上的学生姓名、课程名称和分数。
使用INNER JOIN + WHERE
SELECT
s.s_name AS student_name,
c.c_name AS course_name,
sc.score
FROM sc
JOIN stu s ON sc.sid = s.sid
JOIN cour c ON sc.cid = c.cid
WHERE sc.score > 70
ORDER BY s.s_name, sc.score DESC;
9、查询每个学生的月平均上课时间
SELECT
s.sid,
s.s_name,
ROUND(AVG(monthly_hours), 2) AS avg_monthly_hours
FROM (
SELECT
ct.sid,
DATE_TRUNC('month', ct.create_time) AS month,
SUM(EXTRACT(EPOCH FROM (ct.end_time - ct.create_time))/3600) AS monthly_hours
FROM cour_t ct
GROUP BY ct.sid, DATE_TRUNC('month', ct.create_time)
) t
JOIN stu s ON t.sid = s.sid
GROUP BY s.sid, s.s_name
ORDER BY avg_monthly_hours DESC;
10、查询每个学生月最大连续上课天数
使用窗口函数 + 分组计算
WITH daily_attendance AS (
-- 先按天去重,避免同一天多次上课
SELECT DISTINCT
sid,
DATE(create_time) AS attend_date,
DATE_TRUNC('month', create_time) AS month
FROM cour_t
),
date_gaps AS (
-- 使用窗口函数标记连续分组
SELECT
sid,
month,
attend_date,
attend_date - ROW_NUMBER() OVER (
PARTITION BY sid, month
ORDER BY attend_date
)::int AS date_group
FROM daily_attendance
),
continuous_days AS (
-- 计算每个连续组的天数
SELECT
sid,
month,
COUNT(*) AS continuous_days,
MIN(attend_date) AS start_date,
MAX(attend_date) AS end_date
FROM date_gaps
GROUP BY sid, month, date_group
)
-- 取每个学生每月的最大连续天数
SELECT
s.sid,
s.s_name,
TO_CHAR(c.month, 'YYYY-MM') AS month,
MAX(c.continuous_days) AS max_continuous_days,
-- 可选:显示最长连续上课的起止日期
MAX(c.continuous_days) || '天 (' ||
MIN(c.start_date) FILTER (WHERE c.continuous_days = MAX(c.continuous_days) OVER (PARTITION BY c.sid, c.month)) ||
' 至 ' ||
MAX(c.end_date) FILTER (WHERE c.continuous_days = MAX(c.continuous_days) OVER (PARTITION BY c.sid, c.month)) ||
')' AS details
FROM continuous_days c
JOIN stu s ON c.sid = s.sid
GROUP BY s.sid, s.s_name, c.month
ORDER BY s.sid, c.month;