行转列是解决“同一维度多行→同一行多列”统计需求的必要手段,核心写法为case when+group by+聚合函数;pivot仅限部分数据库且不支持动态列,灵活场景需应用层拼sql或动态sql。

行转列不是语法糖,是解决“同一维度多行 → 同一行多列”这类统计需求的必要手段。它直接决定你能否在一张视图里干净地展示「每个产品 + 各月销售额」或「每位学生 + 各科成绩」——不靠应用层拼接,也不靠临时表中转。
为什么CASE WHEN + GROUP BY 是最稳的行转列写法
几乎所有 SQL 引擎都支持 CASE WHEN 和聚合函数,这意味着你写的语句能从 MySQL 5.7、PostgreSQL 10、SQL Server 2008 一路跑通到最新版。
常见错误现象:SELECT product_id, CASE WHEN month='Jan' THEN sales END AS jan_sales FROM sales —— 这样写会为每个原始行输出一行,结果里一个产品出现多次,根本没“合并”。
正确做法必须带 GROUP BY 和聚合函数:
- 用
SUM()或MAX()消除重复行(无数据时补 0 要用ELSE 0) - 每个目标列对应一个
CASE WHEN ... THEN value ELSE 0 END结构 -
GROUP BY字段必须是最终要保留的“行标识字段”,比如product_id或student_name
示例(学生科目成绩汇总):
SELECT student_name, SUM(CASE WHEN subject = '语文' THEN score ELSE 0 END) AS 语文, SUM(CASE WHEN subject = '数学' THEN score ELSE 0 END) AS 数学, SUM(CASE WHEN subject = '英语' THEN score ELSE 0 END) AS 英语 FROM scores GROUP BY student_name;
PIVOT 语句只在特定数据库里省事,但有硬限制
PIVOT 在 SQL Server、Oracle、Snowflake 和 MySQL 8.0+ 中可用,但它不是“万能快捷键”。它的本质是语法封装,背后仍依赖聚合逻辑。
容易踩的坑:
-
IN子句里的列名必须是**字面量**,不能是变量或子查询结果(即不支持动态列) - 列值含空格、特殊字符时,必须用方括号
[Q1 Sales]或双引号"Q1 Sales"包裹 - 如果源数据中某个 pivot 值完全缺失(比如没人考过“物理”),该列在结果中仍会出现,但全为
NULL,需手动ISNULL([物理], 0)处理
SQL Server 示例(季度销售):
SELECT year, ISNULL([Q1], 0) AS Q1, ISNULL([Q2], 0) AS Q2 FROM ( SELECT year, quarter, amount FROM sales_by_qtr ) AS src PIVOT ( SUM(amount) FOR quarter IN ([Q1], [Q2]) ) AS pvt;
创建汇总视图时,别忽略 NULL 和数据类型对齐
视图不是一次性快照,而是可复用的逻辑层。一旦底层字段类型不一致或 NULL 处理粗放,下游 JOIN 或 WHERE 就可能出错。
关键细节:
- 所有
CASE WHEN分支返回值类型要一致:避免THEN 100和ELSE 'N/A'混用,否则整列被转成字符串,后续无法参与数值计算 - 用
COALESCE(..., 0)或ISNULL(..., 0)替代裸ELSE NULL,防止视图字段默认为 nullable 导致下游判断失准 - 若 pivot 列来自用户输入(如报表参数中的月份范围),不要硬编码
IN ('2024-01', '2024-02')—— 视图无法参数化,此时应退回到CASE WHEN+ 应用层生成 SQL
动态列场景下,PIVOT 不顶用,得靠应用层拼 SQL
真实业务里,“要展示哪几个月”往往由前端筛选决定,列名无法预知。这时候 PIVOT 的 IN 子句就卡死——它不接受变量。
可行路径只有两条:
- 在应用代码里查出所有待 pivot 的值(如
SELECT DISTINCT sale_month FROM sales WHERE year = 2024),拼出完整CASE WHEN表达式再执行 - 用存储过程 + 动态 SQL(SQL Server 的
sp_executesql,MySQL 的PREPARE/EXECUTE),但视图本身无法动态,只能做成存储过程或函数
换句话说:**没有“自动适配任意列数”的标准 SQL 视图写法**。所谓“灵活”,代价是脱离纯声明式 SQL,进入命令式构造阶段。











