行转列必须用聚合函数配合group by,因case when仅控制单行取值,不压缩行数;漏group by或聚合函数会导致全表坍缩、报错或null泛滥。

为什么单独写 CASE WHEN 无法完成行转列
直接在 SELECT 里写多个 CASE WHEN 却不加 GROUP BY 和聚合函数,结果一定是错的:要么每行都输出、其他列全为 NULL,要么报 ERROR 1055(MySQL 5.7+ 严格模式下)。因为 CASE WHEN 只是表达式,它不改变行数,也不压缩数据——它只决定“这一行该填什么值”。而行转列的本质是“把多行压缩成一行”,这个压缩动作必须靠聚合函数触发。
常见错误写法示例:
SELECT name, CASE WHEN subject = '语文' THEN score END AS 语文, CASE WHEN subject = '数学' THEN score END AS 数学 FROM student;
这段语句会返回原始行数,比如张三有三条记录,就输出三行,其中两行的“语文”或“数学”列是 NULL。这不是你要的“张三 | 80 | 90”格式。
MAX() 和 SUM() 在行转列中怎么选
选哪个聚合函数,取决于字段类型和业务逻辑是否允许重复、是否需要累加:
-
MAX(CASE WHEN ...)更通用:适合字符串、日期、单值成绩等场景。只要有一行匹配,就取该值;多行匹配时取字典序/数值最大值(注意不是随机);对空值容忍度高,MAX(NULL, NULL, 95)返回95 -
SUM(CASE WHEN ...)仅适用于数值型且语义上可累加的字段,比如订单金额、点击量。它自动忽略NULL,但若误用于非唯一科目(如一个学生两门“数学”成绩),会把两个分加起来,变成逻辑错误 - 两者都建议显式写
ELSE 0或ELSE NULL,避免隐式转换干扰类型推断(比如字符串字段被SUM强转成数字后变0)
例如同一学生多次考试同一科目,用 MAX 取最高分合理;若要统计总分,则必须用 SUM,且需确认“同一科目多条记录”是合法业务场景。
GROUP BY 字段漏写会导致什么
GROUP BY 不是可选项,它是行转列的强制锚点。漏掉或写错,后果严重:
- 完全不写
GROUP BY→ 所有数据坍缩成一行,MAX返回整个表的最大值,失去用户粒度 - 只写
GROUP BY name,但SELECT中还有grade字段(非聚合、也未出现在GROUP BY)→ MySQL 报错ERROR 1055,除非关严格模式 - 正确写法必须包含所有非聚合字段:比如要展示
name、grade和各科成绩,GROUP BY就得是GROUP BY name, grade
典型正确结构:
SELECT name, grade, MAX(CASE WHEN subject = '语文' THEN score END) AS 语文, MAX(CASE WHEN subject = '数学' THEN score END) AS 数学 FROM students s JOIN scores sc ON s.id = sc.student_id GROUP BY name, grade;
NULL 处理不当会让数据“消失”而不报错
这是最隐蔽的坑:MySQL 的 SUM() 和 MAX() 遇到全 NULL 输入时,都返回 NULL,而不是 0 或空字符串。BI 工具或前端常把 NULL 渲染为空白,看起来像“没数据”,实则是“有数据但全是空值”。
- 别用
IFNULL(MAX(...), 0)包裹整个聚合,应优先在CASE内部写ELSE 0,更早切断NULL传播 -
COALESCE(SUM(...), 0)是安全兜底,但不如从源头控制(比如SUM(CASE WHEN ... THEN score ELSE 0 END)) - 字符串字段慎用
ELSE 0,可能引发隐式转码(如'95'和0混合导致整列变0),统一用ELSE NULL更稳妥
真正卡住人的地方,往往不是语法写不对,而是没意识到:行转列不是“写几个 CASE 就完事”,而是“用聚合函数强行把多行压进一行”,中间任何一环(GROUP BY、聚合函数、NULL 控制)缺位,结果就不可控。











