SQL Server中特定行转列:[dbo].[obs]表数据转换需求
正确实现行转列(SECTION转列)的SQL方法
你用UNPIVOT是搞反了——UNPIVOT是列转行操作,而你需要的是行转列,应该用PIVOT或条件聚合来实现。以下分两种场景给出解决方案:
一、静态行转列(SECTION取值固定已知)
如果SECTION的可能取值是固定的(比如只有A、B、C),直接用PIVOT语法即可:
SELECT NIN, [A], [B], [C] FROM ( SELECT NIN, SECTION, RESULT FROM [dbo].[obs] ) AS SourceTable PIVOT ( MAX(RESULT) -- 若每个NIN+SECTION组合唯一,用MAX/MIN/SUM效果一致 FOR SECTION IN ([A], [B], [C]) -- 列出所有SECTION的固定取值 ) AS PivotTable;
如果需要更好的兼容性(适配所有SQL Server版本),可以用条件聚合写法:
SELECT NIN, MAX(CASE WHEN SECTION = 'A' THEN RESULT END) AS [A], MAX(CASE WHEN SECTION = 'B' THEN RESULT END) AS [B], MAX(CASE WHEN SECTION = 'C' THEN RESULT END) AS [C] FROM [dbo].[obs] GROUP BY NIN;
二、动态行转列(SECTION取值不固定/会新增)
如果SECTION的取值是动态变化的,没法提前写死,可用动态SQL自动生成列列表:
SQL Server 2017及以上版本(支持STRING_AGG)
DECLARE @columns NVARCHAR(MAX), @sql NVARCHAR(MAX); -- 生成所有SECTION唯一值的列名列表 SELECT @columns = STRING_AGG(QUOTENAME(SECTION), ', ') FROM (SELECT DISTINCT SECTION FROM [dbo].[obs]) AS s; -- 拼接并执行动态SQL SET @sql = N' SELECT NIN, ' + @columns + N' FROM ( SELECT NIN, SECTION, RESULT FROM [dbo].[obs] ) AS SourceTable PIVOT ( MAX(RESULT) FOR SECTION IN (' + @columns + N') ) AS PivotTable;'; EXEC sp_executesql @sql;
SQL Server 2016及以下版本(用FOR XML PATH拼接)
DECLARE @columns NVARCHAR(MAX), @sql NVARCHAR(MAX); -- 生成所有SECTION唯一值的列名列表 SELECT @columns = STUFF(( SELECT DISTINCT ', ' + QUOTENAME(SECTION) FROM [dbo].[obs] FOR XML PATH(''), TYPE ).value('.', 'NVARCHAR(MAX)'), 1, 2, ''); -- 拼接并执行动态SQL SET @sql = N' SELECT NIN, ' + @columns + N' FROM ( SELECT NIN, SECTION, RESULT FROM [dbo].[obs] ) AS SourceTable PIVOT ( MAX(RESULT) FOR SECTION IN (' + @columns + N') ) AS PivotTable;'; EXEC sp_executesql @sql;
为什么你的UNPIVOT写法不对?
UNPIVOT的作用是把多列(比如已存在的A、B、C列)转换成SECTION和RESULT的行数据,和你当前"把行转成列"的需求完全相反,所以结果不符合预期。
内容的提问来源于stack exchange,提问作者Miiro Bels
相关产品推荐
相关产品推荐

