SQL Server教程-列转行:UNPIVOT 从固定到动态
当前位置:点晴教程→知识管理交流
→『 技术文档交流 』
变成这样: 这就是列转行,也叫"逆透视"(Unpivot)。 SQL Server 提供了两条路:
用一个完整的学生成绩案例,带你从头到尾搞定。 先建测试数据CREATE TABLE ScoreTable ( StudentName NVARCHAR(20), 语文 INT, 数学 INT, 英语 INT ); INSERT INTO ScoreTable VALUES ('张三', 88, 92, 85), ('李四', 76, 88, 91), ('王五', 95, 87, 78); 原始数据(一行一人): 转换目标(一行一成绩): 方式一:静态 UNPIVOT适用场景:列名固定,你提前知道要转哪几列。 SELECT StudentName, Subject, Score FROM ScoreTable UNPIVOT ( Score -- 新生成的"值列"的列名 FOR Subject -- 新生成的"列名列"的列名 IN (语文, 数学, 英语) ) AS up; 语法拆解: UNPIVOT ( 值列名 FOR 列名列名 IN (要转的列1, 列2, ...) ) AS 别名
执行结果正是我们要的格式 ✅ 静态 UNPIVOT 的致命缺陷列名是写死的。如果后期加了一列「物理」,或者列名本身就是动态的(比如每个月的销售额列),静态写法就废了——你得一直改 SQL。 这就是动态 UNPIVOT 的用武之地。 方式二:动态 UNPIVOT核心思路:先查出所有要转的列名,自动拼出
这样即使以后加了「物理」列,SQL 也不用改,自动适配 ✅ 兼容 SQL Server 2016 及以下(FOR XML PATH 拼列名)如果你的环境不支持 SELECT @cols = STUFF( ( SELECT ',' + QUOTENAME(COLUMN_NAME) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'ScoreTable' AND COLUMN_NAME <> 'StudentName' ORDER BY ORDINAL_POSITION FOR XML PATH('') ), 1, 1, '' -- 去掉开头多余的逗号 ); 效果与 两种方式 + 手动方式对比一个容易踩的坑UNPIVOT 会自动过滤掉 NULL 值。 -- 王五的英语成绩是 NULL INSERT INTO ScoreTable VALUES ('赵六', 80, 90, NULL); -- UNPIVOT 后,赵六只有 2 行记录(语文、数学),英语那行直接消失 SELECT StudentName, Subject, Score FROM ScoreTable UNPIVOT ( Score FOR Subject IN (语文, 数学, 英语) ) AS up; 原因:UNPIVOT 的内部实现等价于把各列值拿出做 如果需要保留 NULL 行,改用 -- 保留 NULL 行的写法 SELECT StudentName, '语文' AS Subject, 语文 AS Score FROM ScoreTable UNION ALL SELECT StudentName, '数学' AS Subject, 数学 AS Score FROM ScoreTable UNION ALL SELECT StudentName, '英语' AS Subject, 英语 AS Score FROM ScoreTable; -- 赵六的英语行会保留,Score 为 NULL 小结列转行两步走:
记住一个原则:UNPIVOT 会悄悄吃掉 NULL 行,如果业务上 NULL 也有意义,一定要用兜底方案。 该文章在 2026/6/24 9:53:56 编辑过 |
关键字查询
相关文章
正在查询... |