SQL Server存储过程中Group By分组统计班级数结果异常问题
问题原因
存储过程统计结果错误,核心是两处逻辑缺陷:
- 班级数统计未去重:Class与Student是一对多关系,左连接后1个班级关联N名学生就会生成N行结果,直接用
COUNT(Degree)统计行数,会把同一班级对应的重复学生行全部计入,导致数值偏大。比如测试数据中1st年级共2个班级,每个班级对应2名学生,连接后生成4行,计数就返回了错误值4。 - 汇总行关联逻辑有隐患:UNION ALL的汇总部分使用
INNER JOIN关联两表,如果后续新增没有学生的班级,这类班级会被内连接过滤,导致总班级数统计缺失。
修正方案
统计班级数时使用COUNT(DISTINCT C.CId)对班级ID去重计数,统计学生数时使用COUNT(S._SId)(COUNT会自动忽略左连接产生的NULL值,准确统计学生数量),汇总部分也改用左连接避免漏算无学生的班级。
修正后的存储过程代码如下:
ALTER PROCEDURE dbo.FirstReport AS BEGIN -- 按年级分组统计 SELECT Degree, COUNT(DISTINCT C.CId) AS numberOfClasses, COUNT(S._SId) AS numberOfStudents FROM Class C LEFT OUTER JOIN Student S ON C.CId = S.StudentClass GROUP BY Degree UNION ALL -- 全量汇总统计 SELECT 'SUM' AS Degree, COUNT(DISTINCT C.CId), COUNT(S._SId) FROM Class C LEFT OUTER JOIN Student S ON C.CId = S.StudentClass; END
执行后将返回正确结果:
| Degree | numberOfClasses | numberOfStudents |
|---|---|---|
| 1st | 2 | 4 |
| 2nd | 2 | 1 |
| 3rd | 1 | 0 |
| SUM | 5 | 5 |
如果希望简化代码,也可以用WITH ROLLUP语法省略UNION ALL的重复查询,逻辑完全等价,后续维护更方便:
ALTER PROCEDURE dbo.FirstReport AS BEGIN SELECT CASE WHEN GROUPING(C.Degree) = 1 THEN 'SUM' ELSE C.Degree END AS Degree, COUNT(DISTINCT C.CId) AS numberOfClasses, COUNT(S._SId) AS numberOfStudents FROM Class C LEFT OUTER JOIN Student S ON C.CId = S.StudentClass GROUP BY C.Degree WITH ROLLUP; END
内容的提问来源于stack exchange,提问作者Aylin Naebzadeh
相关产品推荐
相关产品推荐

