MySQL 5.7中如何为每个学生的每个分组提取前2高分?
解决MySQL 5.7中按学生+GroupCode提取前2高分的问题
看起来你需要的是每个学生在对应groupcode下的前2个最高分数,而不是整个groupcode的前2名——这也是你当前的SELECT marks FROM person WHERE groupCode = 1 ORDER BY marks DESC LIMIT 2查询没得到预期结果的原因,它只会返回整个groupcode=1中的top2分数,而不是针对每个学生单独提取。
针对MySQL 5.7(不支持窗口函数),可以用以下两种方案实现需求:
方案1:使用相关子查询统计排名
这种方法适合数据量不大的场景,逻辑直观:
SELECT p.student_name, p.groupCode, p.marks FROM person p WHERE ( -- 统计同一学生、同一groupCode下,分数大于当前记录的数量 SELECT COUNT(*) FROM person p2 WHERE p2.student_name = p.student_name AND p2.groupCode = p.groupCode AND p2.marks > p.marks ) < 2 -- 分数大于当前的数量小于2,说明当前是前2高 ORDER BY p.groupCode, p.student_name, p.marks DESC;
如果只想查看groupcode=1的情况,只需添加groupCode = 1条件:
SELECT p.student_name, p.marks FROM person p WHERE p.groupCode = 1 AND ( SELECT COUNT(*) FROM person p2 WHERE p2.student_name = p.student_name AND p2.groupCode = p.groupCode AND p2.marks > p.marks ) < 2 ORDER BY p.student_name, p.marks DESC;
方案2:使用用户变量实现高效排名
如果数据量较大,用用户变量的方式性能更优,它能在一次扫描中完成排名计算:
SELECT student_name, groupCode, marks FROM ( SELECT student_name, groupCode, marks, -- 跟踪当前学生、组和分数,动态计算排名 @rank := IF(@current_student = student_name AND @current_group = groupCode, IF(@current_marks = marks, @rank, @rank + 1), 1) AS rank, @current_student := student_name, @current_group := groupCode, @current_marks := marks FROM person -- 初始化变量 CROSS JOIN (SELECT @current_student := '', @current_group := '', @rank := 0, @current_marks := 0) vars -- 按学生、组、分数降序排序,确保排名逻辑正确 ORDER BY student_name, groupCode, marks DESC ) ranked WHERE rank <= 2;
这个查询会先给每个学生+groupCode的组合内的分数按降序排名,然后筛选出排名前2的记录,完全符合你的需求。
内容的提问来源于stack exchange,提问作者JohnKibika
相关产品推荐
相关产品推荐

