
本文介绍如何通过 sql 的条件聚合(case when + sum/avg)将原始“长格式”学生成绩表,动态转为按科目横向展开的“宽格式”html 表格,并正确计算各科平均分。
本文介绍如何通过 sql 的条件聚合(case when + sum/avg)将原始“长格式”学生成绩表,动态转为按科目横向展开的“宽格式”html 表格,并正确计算各科平均分。
在实际教学管理系统中,数据库通常以规范化形式存储成绩数据(即每行一条记录:学生ID、学期、科目、分数),但前端展示常需按科目分组、按学期横向排列——这属于典型的行转列(Pivot)场景。由于标准 SQL 不直接支持 PIVOT(MySQL 8.0+ 虽有窗口函数增强,但仍无原生 PIVOT 语法),我们采用 条件聚合(Conditional Aggregation) 这一兼容性强、逻辑清晰的方案。
核心思路是:
- 按
subjects分组(确保每个科目一行); - 使用
CASE WHEN term = 'X' THEN score END提取对应学期的分数; - 对该表达式应用聚合函数(如
SUM或MAX)——因每科每学期仅一条记录,SUM、MAX、MIN效果一致,此处用SUM简洁且语义明确; - 使用
AVG()计算该科目所有学期的平均分,并通过TRUNCATE(..., 2)保留两位小数(也可用ROUND,视精度需求而定)。
✅ 正确的 SQL 查询如下:
SELECT subjects AS 'SUBJECT', SUM(CASE WHEN term = 'Term 1' THEN score END) AS 'TERM ONE', SUM(CASE WHEN term = 'Terminal' THEN score END) AS 'TERMINAL', TRUNCATE(AVG(score), 2) AS 'AVERAGE' FROM examresults GROUP BY subjects;
⚠️ 注意事项:
- 原查询中
GROUP BY subject, term错误地将分组粒度设为“科目+学期”,导致无法跨学期聚合,应改为仅GROUP BY subjects; -
DISTINCT与GROUP BY混用通常冗余,且可能掩盖逻辑错误; - 若存在某科目在某学期无成绩,对应字段将返回
NULL(HTML 中显示为空),如需默认值(如0),可嵌套COALESCE(SUM(...), 0); - 表名
examresults和字段名(stid,term,subjects,score)请根据实际数据库结构调整;若stid需筛选特定学生(如'STD-1'),应在WHERE子句中添加:WHERE stid = 'STD-1'(置于GROUP BY前)。
? 扩展建议:
- 若学期名称不固定(如新增
Term 2),需手动扩展CASE分支;生产环境可结合应用层动态拼接 SQL,或升级至 MySQL 8.0+ 后使用JSON_OBJECTAGG+ 应用层处理; - 为提升可读性,建议在
SELECT中为字段使用反引号包裹含空格或特殊字符的别名(如`TERM ONE`),但本例中单引号亦可被多数驱动接受。
掌握此模式后,你不仅能实现成绩表转换,还可灵活应用于销售统计(按产品+月份汇总)、用户行为分析(按功能模块+时间段计数)等各类行列转换需求。










