如何筛选仅选修单门课程的学生学号?窗口函数WHERE子句报错求助
解决SQL窗口函数不能在WHERE/HAVING中使用的问题及需求实现
原SQL的问题分析
- 窗口函数(如
count() over())的执行时机晚于WHERE子句,因此WHERE里无法直接引用窗口函数生成的别名values;HAVING子句需要配合GROUP BY使用,原SQL没有GROUP BY,所以用HAVING也无效。 - 分组逻辑错误:你按拼接后的
key(学号+课程)分区,统计的是每个学号+课程组合的出现次数,而不是每个学生的选修课程总数,这和“筛选仅选修一门课程的学生”的需求不匹配。
正确实现方案
方案一:用GROUP BY + HAVING直接筛选学号
如果只需要获取符合条件的学生学号,这是最简洁的写法:
SELECT roll_number FROM subject_data WHERE roll_number IS NOT NULL AND subject IS NOT NULL GROUP BY roll_number HAVING COUNT(subject) = 1;
- 说明:按学号分组,统计每个学生的选修课程数量;如果同一个学生可能重复选同一门课,需要用
COUNT(DISTINCT subject)去重后统计。
方案二:用子查询/CTE结合窗口函数(需保留课程信息时使用)
如果需要同时保留学生的课程信息,可以先通过子查询或CTE计算每个学生的课程总数,再在外层筛选:
-- 用CTE写法 WITH student_course_stats AS ( SELECT roll_number, subject, COUNT(subject) OVER(PARTITION BY roll_number) AS total_courses FROM subject_data WHERE roll_number IS NOT NULL AND subject IS NOT NULL ) SELECT roll_number, subject FROM student_course_stats WHERE total_courses = 1; -- 或者子查询写法 SELECT roll_number, subject FROM ( SELECT roll_number, subject, COUNT(subject) OVER(PARTITION BY roll_number) AS total_courses FROM subject_data WHERE roll_number IS NOT NULL AND subject IS NOT NULL ) AS temp WHERE total_courses = 1;
- 说明:先通过窗口函数按学号分区,计算每个学生的总课程数,再在外层WHERE中筛选总课程数为1的记录。
内容的提问来源于stack exchange,提问作者Farzam Ashhar
相关产品推荐
相关产品推荐

