sum(case when...)是最稳的行转列写法,因其兼容所有主流sql引擎、执行计划清晰、避免笛卡尔积与空值扩散,且必须配合聚合函数与else 0兜底才能正确收拢多行数据。

为什么直接用 SUM(CASE WHEN ...) 是最稳的行转列写法
因为不需要依赖数据库特有语法(比如 MySQL 的 PIVOT 或 SQL Server 的 PIVOT 关键字),所有主流 SQL 引擎都支持,且执行计划清晰、可控。它本质是“对每行做条件判断 + 聚合累加”,天然适配 GROUP BY,不会产生隐式笛卡尔积或空值扩散。
CASE WHEN 必须配合 SUM(或 COUNT/AVG)才能出列
单独写 CASE WHEN type = 'A' THEN amount END 只会生成一列含 NULL 的结果,无法把多行的 A/B/C 值收拢到同一行。必须用聚合函数把“属于 A 的所有 amount”加总(哪怕业务上每个 type 每组只出现一次,也得用 SUM 来触发行压缩)。
常见错误现象:
- 忘写 SUM,结果行数没变,只是多了几列 NULL
- 用 MAX 或 MIN 替代 SUM —— 当存在重复 type 时逻辑可能错,SUM 更符合“汇总”语义,且对单值场景完全等价
- 正确写法:
SUM(CASE WHEN type = 'A' THEN amount ELSE 0 END) - 别写
CASE WHEN type = 'A' THEN amount END(缺聚合) - 别写
SUM(CASE WHEN type = 'A' THEN amount END)(缺ELSE 0,NULL 会污染求和结果)
GROUP BY 字段必须覆盖所有非聚合列
例如你按用户统计各类型金额,user_id 就是必须出现在 GROUP BY 中的字段;如果还选了 region,那 region 也得进 GROUP BY,否则报错(如 PostgreSQL / MySQL 8.0+ 严格模式)。
容易踩的坑:
- 把本该分组的字段漏写,导致聚合结果被意外合并
- 在 SELECT 中写了 name 却没在 GROUP BY 中包含,报 column "name" must appear in the GROUP BY clause
示例:
SELECT user_id, SUM(CASE WHEN type = 'A' THEN amount ELSE 0 END) AS amt_a, SUM(CASE WHEN type = 'B' THEN amount ELSE 0 END) AS amt_b FROM orders GROUP BY user_id;
性能关键:WHERE 先过滤,再 CASE
把条件判断塞进 CASE WHEN 里不耗性能,但若能提前用 WHERE 排除大量无关行(比如只查最近 30 天),就能显著减少参与聚合的数据量。CASE 内部的 ELSE 0 是必要兜底,但不能代替 WHERE 过滤。
- 好:
WHERE created_at >= '2024-01-01' AND type IN ('A','B','C') - 坏:去掉 WHERE,全表扫 + 在 CASE 里判断 type,IO 和 CPU 都浪费
- 注意:
type IN ('A','B','C')放 WHERE 比放 CASE 里快,尤其当 type 有索引时
复杂点在于:当列值本身带空格、大小写混杂、或需模糊匹配(如 LIKE '%refund%')时,CASE 内部的判断逻辑就得更谨慎,此时建议先清洗数据或建计算列索引——这些细节往往比写法本身更影响效率。










