Oracle数据库行转列问题:CASE语句无法合并多测试分数至单行
解决Oracle行转列后分数分散多行的问题
嘿,我完全懂你遇到的麻烦——你想用CASE把ACT的各个科目转成列,但现在结果里每一行只显示一个科目的分数,其他列都是NULL,没法把同一个学生同一次测试的所有分数合并到一行对吧?这是因为你的查询没有做分组聚合,每个测试分数的原始行都会单独输出,CASE只会在匹配到对应科目的行填充值,其他行自然是空的。
解决方案:用聚合函数+GROUP BY合并行
我们可以用MAX()(或者SUM(),这里每个学生同一次测试每个科目只有一个有效分数,两者效果一致)包裹CASE语句,然后通过GROUP BY把同一个学生同一次测试的所有行合并成一行。同时我把旧的隐式连接改成了显式INNER JOIN,让SQL更清晰易读:
SELECT schools.name AS School, s.lastfirst AS Student, s.student_number, s.grade_level, t.name AS Test_Name, TO_CHAR(st.test_date) AS Test_Date, -- 给日期列加别名,方便GROUP BY和查看 MAX(CASE WHEN ts.name = 'ACT_Reading' THEN sts.numscore END) AS ACT_Reading, MAX(CASE WHEN ts.name = 'ACT_Math' THEN sts.numscore END) AS ACT_Math, MAX(CASE WHEN ts.name = 'ACT_English' THEN sts.numscore END) AS ACT_English, MAX(CASE WHEN ts.name = 'ACT_Science' THEN sts.numscore END) AS ACT_Science, MAX(CASE WHEN ts.name = 'ACT_Composite' THEN sts.numscore END) AS ACT_Composite FROM students s INNER JOIN studenttestscore sts ON s.id = sts.studentid INNER JOIN studenttest st ON sts.studenttestid = st.id INNER JOIN testscore ts ON sts.testscoreid = ts.id INNER JOIN test t ON ts.testid = t.id INNER JOIN schools ON s.schoolid = schools.school_number WHERE t.name = 'ACT' AND sts.numscore > 0 AND s.enroll_status = 0 AND s.schoolid = 10 GROUP BY schools.name, s.lastfirst, s.student_number, s.grade_level, t.name, TO_CHAR(st.test_date) -- 分组要包含所有非聚合的列 ORDER BY s.lastfirst, st.test_date DESC;
关键修改点说明:
- 聚合函数包裹CASE:
MAX(CASE...)会在分组后,把每个科目对应的非NULL分数值保留下来,其他NULL值会被忽略,这样就能在同一行显示所有科目的分数了。 - GROUP BY子句:必须包含所有没有被聚合函数处理的列,确保同一个学生同一次测试的所有行被合并成一行。
- 显式JOIN:替代原来的逗号连接表的写法,让表之间的关联关系更清晰,也更符合现代SQL的编写规范。
额外说明:
如果同一个学生有多次ACT测试,上面的查询会按测试日期分组,也就是每次测试的分数单独成一行。如果你的需求是获取每个学生最新一次ACT测试的所有科目分数,可以先通过子查询筛选出每个学生每个科目的最新测试记录,再进行行转列~
内容的提问来源于stack exchange,提问作者JBrown
相关产品推荐
相关产品推荐

