按Varchar字段分组异常:如何获取课程最后一次修读成绩?
解决方法:取最后一次修读的成绩而非最高成绩
你的问题核心在于:MAX(GRADE)是取该课程所有修读记录中的最高成绩,但你实际需要的是最后一次修读(对应最大行号)的成绩——这两个逻辑完全不同,当最后一次修读的成绩不是最高分的时候(比如补考分数更低),就会出现错误结果。
下面提供两种可靠的实现方法:
方法1:使用窗口函数ROW_NUMBER()(推荐)
窗口函数是处理这类“分组取最新/最后一条记录”场景的最优方案,逻辑清晰且性能较好:
WITH RankedCourses AS ( SELECT NAME, COURSE, HRSCODE, GRADE, -- 按学生、课程、HRSCODE分组,组内按行号降序排名,最后一次修读的记录排第1 ROW_NUMBER() OVER (PARTITION BY NAME, COURSE, HRSCODE ORDER BY ROW_NUM DESC) AS rn FROM #TEMP ) SELECT NAME, COURSE, HRSCODE, GRADE FROM RankedCourses WHERE rn = 1; -- 只取每组排名第1的记录(最后一次修读)
说明:
PARTITION BY NAME, COURSE, HRSCODE:将相同学生、相同课程、相同HRSCODE的记录划分为一组ORDER BY ROW_NUM DESC:组内按行号从大到小排序,行号最大的记录(最后一次修读)会被标记为rn=1- 最后筛选
rn=1的记录,就能得到每个课程最后一次修读的成绩
方法2:使用关联子查询
如果你使用的数据库不支持窗口函数(不过现在主流数据库都支持),可以用关联子查询实现:
SELECT t1.NAME, t1.COURSE, t1.HRSCODE, t1.GRADE FROM #TEMP t1 WHERE t1.ROW_NUM = ( -- 找到当前学生+课程+HRSCODE对应的最大行号(最后一次修读的行号) SELECT MAX(t2.ROW_NUM) FROM #TEMP t2 WHERE t2.NAME = t1.NAME AND t2.COURSE = t1.COURSE AND t2.HRSCODE = t1.HRSCODE );
说明:
- 子查询会为每条记录找到同组内的最大行号,外层查询筛选出行号等于这个最大值的记录,也就是最后一次修读的成绩
为什么原来的GROUP BY方法不行?
举个例子:假设Math科目学生第一次修读(行号1)成绩是80,第二次补考(行号2)成绩是70。MAX(GRADE)会返回80,但你需要的是行号2对应的70——这就是原来的查询逻辑不符合需求的根本原因。
内容的提问来源于stack exchange,提问作者Rick
相关产品推荐
相关产品推荐

