SUM 和 CASE WHEN 是 MySQL 行转列最稳定方案,因 MySQL 官方至今无原生 PIVOT 语法;核心是用 CASE WHEN 判断分类、SUM 聚合取值,必须配合 GROUP BY,且推荐写 ELSE 0 避免 NULL 导致结果异常。

SUM 和 CASE WHEN 是 MySQL 实现行转列最稳定、兼容性最好的组合,不需要依赖 MySQL 8.0+ 的 PIVOT,也不需要动态 SQL 或存储过程。
为什么不用 PIVOT?
MySQL 官方至今(2026 年)**没有原生 PIVOT 语法**。网上提到的“MySQL 8.0 PIVOT 函数”是误传或混淆了其他数据库(如 SQL Server、Oracle)的特性。你执行 SELECT * FROM t PIVOT(...) 会直接报错:ERROR 1064 (42000): You have an error in your SQL syntax。
SUM(CASE WHEN ...) 的写法要点
核心逻辑是:对每个目标列,用 CASE WHEN 判断是否命中该分类值,命中则取原始数值,否则取 0;再用 SUM 聚合——因为同一分组下,每行最多只匹配一个 WHEN 分支,所以 SUM 等价于“取值”,且能绕过 NULL 导致聚合失败的问题。
- 必须配合
GROUP BY,否则所有行被压成一行,失去分组意义 - 用
SUM比MAX更安全:即使原始数据含NULL,SUM(NULL, 10)= 10;而MAX(NULL, 10)也等于 10,但若全为NULL,MAX返回NULL,SUM返回0,语义更明确 - 不要用
AVG或COUNT直接套,除非你真要算均值或频次——它们会改变业务含义 - 字段别名建议统一加后缀,比如
Jan_sales、Feb_sales,避免和源字段名冲突
常见错误:空值、重复行、漏 GROUP BY
典型翻车现场:
- 忘了
GROUP BY→ 结果只剩一行,所有列都是全表聚合值 - 源数据里同一
product_id + month有多条记录,但没确认是否应累加 → 用SUM会自动叠加,用MAX只取最大,需按业务定 -
CASE WHEN month = 'Jan' THEN sales END没写ELSE 0→ 匹配不到时返回NULL,SUM会跳过NULL,结果变成NULL而非 0,前端展示容易出空格或报错 - 月份字段含空格或大小写不一致,比如
'jan '≠'Jan'→ 建议先SELECT DISTINCT TRIM(UPPER(month)) FROM sales排查
替代方案对比:GROUP_CONCAT 不是行转列
GROUP_CONCAT 常被误当作行转列工具,但它只是把多行拼成一个逗号分隔字符串,例如:GROUP_CONCAT(sales) → '100,150,120'。这不是真正的列结构,无法被 BI 工具识别为独立字段,也不能参与数值计算。它适合导出摘要,不适合构建报表宽表。
真正需要列结构时,坚持用 CASE WHEN + 聚合函数,哪怕要手写 12 个 MONTH 分支——这是可控、可读、可维护的底线方案。











