如何将同一主键的多行数据转行成多列?Pivot实现求助
嘿,我完全懂你的困扰!你现在需要把原本按行展示的不同t3.description对应的金额,转成列来和t1.id、t1.name放在同一行,也就是典型的行转列需求,而且因为t3.description的取值不固定,静态Pivot确实不好用,我来给你一步步拆解解决方案:
先理解静态Pivot(适合已知固定列的情况)
如果暂时你知道所有可能的t3.description取值,可以先用静态Pivot来实现,这样能帮你快速理解Pivot的核心逻辑:
SELECT t1.id, t1.name, [TEST DESC. 1], [TEST DESC. 2] FROM ( -- 这里是你的基础查询,先获取需要转置的原始数据 SELECT t1.id, t1.name, t3.description, t3.amount FROM table1 (nolock) t1 JOIN table2 (nolock) t2 ON t1.t2_id = t2.id JOIN table3 (nolock) t3 ON t2.t3_id = t3.id ) AS SourceData PIVOT ( MAX(amount) -- 因为每个(id, description)对应唯一金额,用MAX/AVG/SUM都可以,这里选MAX FOR description IN ([TEST DESC. 1], [TEST DESC. 2]) -- 指定要转成列的description值 ) AS PivotTable;
这个查询会把你指定的description值作为列名,对应的amount填充到列里,就能得到你想要的结果格式。但问题是如果有新的description出现,你就得手动修改IN里的列表,所以接下来给你适配动态列的方案。
动态Pivot(适配不固定的
t3.description取值) 这个方案会自动获取所有不同的t3.description值,动态生成列名,完全不需要手动维护:
DECLARE @PivotColumns NVARCHAR(MAX); DECLARE @DynamicSQL NVARCHAR(MAX); -- 第一步:动态获取所有不同的description,拼接成带方括号的列名字符串 SELECT @PivotColumns = STRING_AGG(QUOTENAME(description), ', ') FROM ( SELECT DISTINCT t3.description FROM table1 (nolock) t1 JOIN table2 (nolock) t2 ON t1.t2_id = t2.id JOIN table3 (nolock) t3 ON t2.t3_id = t3.id ) AS UniqueDescriptions; -- 第二步:构建动态SQL语句 SET @DynamicSQL = N' SELECT id, name, ' + @PivotColumns + N' FROM ( -- 这里替换成你实际的复杂查询即可 SELECT t1.id, t1.name, t3.description, t3.amount FROM table1 (nolock) t1 JOIN table2 (nolock) t2 ON t1.t2_id = t2.id JOIN table3 (nolock) t3 ON t2.t3_id = t3.id ) AS SourceData PIVOT ( MAX(amount) FOR description IN (' + @PivotColumns + N') ) AS PivotTable;'; -- 执行动态生成的SQL EXEC sp_executesql @DynamicSQL;
几个关键注意点
- 关于
STRING_AGG:这个函数是SQL Server 2017及以上版本支持的,如果你的版本更早,可以用FOR XML PATH来拼接列名,替换第一步的代码:SELECT @PivotColumns = STUFF(( SELECT ', ' + QUOTENAME(description) FROM (SELECT DISTINCT t3.description FROM table1 (nolock) t1 JOIN table2 (nolock) t2 ON t1.t2_id = t2.id JOIN table3 (nolock) t3 ON t2.t3_id = t3.id) AS UniqueDescriptions FOR XML PATH(''), TYPE ).value('.', 'NVARCHAR(MAX)'), 1, 2, ''); - 聚合函数的选择:这里用
MAX(amount)是因为每个(id, description)组合应该只有一个金额值,用MAX、MIN、SUM(因为只有一个值,结果一样)都可以,如果你有重复的组合,根据业务需求选择合适的聚合函数即可。 - 复杂查询适配:只需要把动态SQL里的基础查询部分替换成你实际的复杂查询就行,逻辑完全通用。
内容的提问来源于stack exchange,提问作者user3007447
相关产品推荐
相关产品推荐

