SQL查询最高报名容量比课程,聚合函数内嵌SELECT是否可行?
问题解答
现有写法存在的问题
你给出的写法无法实现需求,核心问题如下:
- 缺少
GROUP BY子句:HAVING是对分组后的聚合结果做过滤,你没有对课程ID分组,聚合逻辑完全不成立,语法层面也会报错。 - 字段使用错误:子查询中出现了不存在的
id_course字段,你的关联表中仅存在id_class字段关联课程ID。 - 统计逻辑错误:子查询的
WHERE条件加入了sc2.id_student=s.id,实际统计的是单个学生在对应课程的报名次数,完全不是你需要的「课程总报名人数」。 HAVING语法错误:HAVING后需要跟布尔判断条件,你仅写了MAX(xxx)没有判断规则,无法通过语法校验。
关于聚合函数内使用子查询的说明
语法层面确实支持在聚合函数中嵌套子查询,但你当前的场景完全不需要这么写,这种写法会对每条关联记录都触发一次子查询,数据量较大时性能会非常差。
更优的实现方案
核心思路
先统计每门课程的总报名人数,计算「报名人数/课程容量」的占比,再筛选出占比最高的课程即可,逻辑清晰性能也更好。
通用实现(兼容所有支持标准SQL的数据库)
SELECT c.id AS class_id FROM class c LEFT JOIN student_class sc ON c.id = sc.id_class GROUP BY c.id, c.capacity HAVING COUNT(sc.id_student) / c.capacity = ( SELECT MAX(occupy_rate) FROM ( SELECT COUNT(sc2.id_student) / c2.capacity AS occupy_rate FROM class c2 LEFT JOIN student_class sc2 ON c2.id = sc2.id_class GROUP BY c2.id, c2.capacity ) AS rate_table )
简化实现(支持CTE和窗口函数的数据库,如MySQL8.0+、PostgreSQL等)
-- 先计算每门课的占用率 WITH class_occupy_rate AS ( SELECT c.id AS class_id, COUNT(sc.id_student) / c.capacity AS occupy_rate FROM class c LEFT JOIN student_class sc ON c.id = sc.id_class GROUP BY c.id, c.capacity ) -- 筛选占比最高的课程,支持返回所有并列最高的结果 SELECT class_id FROM class_occupy_rate WHERE occupy_rate = (SELECT MAX(occupy_rate) FROM class_occupy_rate)
补充说明
- 这里用
LEFT JOIN是为了包含无人报名的课程(占比为0),如果你的需求不需要统计这类课程,换成INNER JOIN即可。 - 如果
student_class表允许同一学生重复报名同一门课,统计人数时把COUNT(sc.id_student)换成COUNT(DISTINCT sc.id_student)即可。 - 两种写法都支持返回所有占比并列最高的课程,不会漏数据。
内容的提问来源于stack exchange,提问作者Spyromancer
相关产品推荐
相关产品推荐

