SQL Server实现带动态列的行转列(convert rows into columns)
SQL Server 无预置列名的动态行转列实现
SQL Server原生PIVOT语法要求硬编码转置后的列名,要实现根据City字段取值自动生成列的效果,通过动态SQL拼接即可完成,不需要提前固定列清单。
实现逻辑
- 先从源表提取所有去重后的City值,转义后拼接为PIVOT需要的列名集合
- 拼接完整的PIVOT查询语句
- 执行动态生成的SQL返回结果
完整代码
假设你的源表名为VisitorPrice,包含[Visitor name]、City、Price三个字段,代码如下:
DECLARE @dynamic_columns NVARCHAR(MAX), @execute_sql NVARCHAR(MAX); -- 生成动态列名清单,自动处理特殊字符转义 -- SQL Server 2017及以上版本可用STRING_AGG写法 SELECT @dynamic_columns = STRING_AGG(QUOTENAME(City), ', ') FROM (SELECT DISTINCT City FROM VisitorPrice) AS unique_city; -- 若使用SQL Server 2016及以下版本,替换上面的列名拼接逻辑为以下FOR XML PATH写法即可 /* SELECT @dynamic_columns = STUFF( (SELECT ', ' + QUOTENAME(City) FROM (SELECT DISTINCT City FROM VisitorPrice) AS unique_city FOR XML PATH(''), TYPE ).value('.', 'NVARCHAR(MAX)'), 1, 2, '') */ -- 拼接PIVOT查询语句 SET @execute_sql = N' SELECT [Visitor name], ' + @dynamic_columns + N' FROM VisitorPrice PIVOT ( MAX(Price) FOR City IN (' + @dynamic_columns + N') ) AS pivot_result '; -- 执行语句输出结果 EXEC sp_executesql @execute_sql;
运行结果
针对你给出的3条Neo的示例数据,执行后会自动生成Japan、NewYork、Paris三个列,返回单条记录如下:
| Visitor name | Japan | NewYork | Paris |
|---|---|---|---|
| Neo | 95000 | 100000 | 1000000 |
注意事项
QUOTENAME()函数用于包裹City字段值,避免城市名包含空格、特殊符号时触发SQL语法错误- PIVOT必须搭配聚合函数使用:如果同一访客、同一城市存在多条价格记录,
MAX(Price)会返回匹配到的最大价格,可根据业务需求替换为SUM、AVG、MIN等其他聚合函数 - 后续源表新增其他城市的记录时,不需要修改代码,查询结果会自动新增对应列
内容的提问来源于stack exchange,提问作者Ali Sharafzade
相关产品推荐
相关产品推荐

