
本文讲解如何通过 sql 的 case 表达式与 group by 配合,将“长格式”学生成绩数据(每行一条科目-学期记录)转换为“宽格式”html 表格所需的结构(每行一个科目,各学期成绩横向展开,并计算平均分)。
本文讲解如何通过 sql 的 case 表达式与 group by 配合,将“长格式”学生成绩数据(每行一条科目-学期记录)转换为“宽格式”html 表格所需的结构(每行一个科目,各学期成绩横向展开,并计算平均分)。
在实际教学管理系统中,原始数据库通常以规范化的“长表”形式存储成绩数据(即每条记录代表一名学生在某学期某科目的得分),但前端 HTML 表格常需以“宽表”形式呈现——即每个学科为一行,不同学期成绩作为独立列。这种转换本质上属于行转列(Pivot)操作,在标准 SQL 中可通过条件聚合高效实现。
核心思路是:按 subjects 分组,对每个分组内不同 term 值使用 CASE WHEN 提取对应 score,再用聚合函数(如 SUM 或 MAX)确保单值输出;同时利用 AVG() 计算该科目的整体平均分,并用 TRUNCATE(..., 2) 控制小数位数。
以下是推荐的可执行 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;
✅ 关键说明:
-
SUM(CASE ... END)在此处等效于MAX或MIN—— 因为每个subjects + term组合唯一(如题设所示),故任一聚合函数均可安全提取单值;SUM写法更通用,且避免NULL导致MAX/MIN异常。 -
AVG(score)自动跨所有学期计算该科目的平均分(非学期均值的平均),符合示例中 “English: (70+85)/2 = 77.5 → 但示例显示为 112.5,存在笔误;实际应为TRUNCATE(AVG(score), 2),即 77.50)。⚠️ 注意:原问题示例中 English 的 AVERAGE 显示为 112.5 明显错误(70+85=155,155/2=77.5),请以逻辑为准,勿机械复制示例数值。 - 若需限定特定学生(如
stid = 'STD-1'),应在WHERE子句中添加:WHERE stid = 'STD-1',置于GROUP BY之前。 - 列别名(如
'TERM ONE')使用单引号包裹,兼容 MySQL;其他数据库(如 PostgreSQL)建议使用双引号或省略引号。
? 进阶提示:
- 若学期名称不固定(如动态新增“Term 2”),静态
CASE将难以维护,此时建议在应用层(PHP/Python)处理 Pivot,或使用数据库特有 Pivot 语法(如 SQL Server 的PIVOT操作符)。 - 输出结果可直接映射为 HTML
<table> 的 <code><tbody> 内容,配合预定义 <code><thead> 即可渲染目标表格。<p>掌握此类条件聚合写法,是构建动态报表与前端友好数据视图的关键基础技能。</p> </thead>










