我有一个表作为MarketOutput有20列
[Region] [LOB] [GWP 2013] [GWP 2014] [LR 2013] [LR 2014] ------------------------------------------------------------- North Workers 38902.50 37,972,404 89 82
我想将列动态更改为行。Region和LOB是固定列,[GWP 2013],[GWP 2014],[LR 2013],[LR 2014]是动态列。
对于明年[GWP 2015],[LR 2015]
[GWP 2015]
[LR 2015]
我想取消透视该列,并将[GWP 2014]拆分为两列[GWP],[2014]。
输出应该像
Region [LOB] [Metrics] [Year] [Value] -------------------------------------------------- North Workers GWP 2013 38902.50 North Workers GWP 2014 37,972,404 North Workers LR 2013 89 North Workers LR 2014 82
你能建议如何做到吗?
我是SQL Server的新手
我也想每次使用动态列表将输出插入到新表中
您只需要在执行以下操作后拆分列UNPIVOT:
UNPIVOT
WITH Unpivoted AS ( SELECT region, lob, columns, value FROM Regions UNPIVOT ( columns FOR value IN([GWP 2013] , [GWP 2014] , [LR 2013] , [LR 2014] , [GWP 2015], [LR 2015]) ) AS u ) SELECT region, lob, columns, CAST(CASE WHEN value LIKE 'GWP%' THEN REPLACE(value,'GWP ', '') WHEN value LIKE 'LR%' THEN REPLACE(value,'LR ', '') END AS INT) AS Year, CASE WHEN value LIKE 'GWP%' THEN 'GWP' WHEN value LIKE 'LR%' THEN 'LR' END AS Metrics FROM Unpivoted;
然后,您当然应该动态地执行此操作,以避免手动列出列并动态地进行操作:
DECLARE @cols AS NVARCHAR(MAX); DECLARE @query AS NVARCHAR(MAX); select @cols = STUFF((SELECT distinct ',' + QUOTENAME(column_name) FROM information_schema.columns WHERE table_name = 'Regions' AND COLUMN_NAME <> 'Region' AND COLUMN_NAME <> 'LOB' FOR XML PATH(''), TYPE ).value('.', 'NVARCHAR(MAX)') , 1, 1, ''); SELECT @query = 'WITH Unpivoted AS ( SELECT region, lob, columns, value FROM Regions UNPIVOT ( columns FOR value IN('+ @cols + ') ) AS u ) SELECT region, lob, columns, CAST(CASE WHEN value LIKE ''GWP%'' THEN REPLACE(value,''GWP '', '''') WHEN value LIKE ''LR%'' THEN REPLACE(value,''LR '', '''') END AS INT) AS Year, CASE WHEN value LIKE ''GWP%'' THEN ''GWP'' WHEN value LIKE ''LR%'' THEN ''LR'' END AS Metrics FROM Unpivoted'; EXECUTE(@query);
假设以下情况,这应该可以正常工作:
[GWP 2013] , [GWP 2014] , [LR 2013] , [LR 2014] , [GWP 2015], [LR 2015], ... etc
所有列都是相同的数据类型int或十进制数,如果数据类型不相同,则应在执行之前unpivot将它们全部转换为一种数据类型,否则会出现错误。
int
unpivot
SQL小提琴演示
这将为您提供:
| region | lob | columns | Year | Metrics | |--------|---------|----------|------|---------| | North | Workers | 38902.5 | 2013 | GWP | | North | Workers | 37972404 | 2014 | GWP | | North | Workers | 70 | 2015 | GWP | | North | Workers | 89 | 2013 | LR | | North | Workers | 82 | 2014 | LR | | North | Workers | 80 | 2015 | LR |
我曾经FOR XML PATH('') ..将所有值列表串联在一个字符串中,这是SQL Server的一种解决方法。的值@cols将是字符串:[GWP 2013], [GWP 2014], ...。
FOR XML PATH('') ..
@cols
[GWP 2013], [GWP 2014], ...
如果您的字段数据类型不同,则必须对所有将在锚点查询中未透视的列进行强制转换,然后再执行UNPVOT以下操作:
UNPVOT
SELECT @query = 'WITH Unpivoted AS ( SELECT region, lob, columns, value FROM ( SELECT region, lob, CAST([GWP 2013] AS DECIMAL(10,2)) AS [GWP 2013], CAST([GWP 2014] AS DECIMAL(10,2)) AS [GWP 2014], ... etc FROM Regions ) AS t UNPIVOT ( columns FOR value IN('+ @cols + ') ) AS u ) SELECT region, lob, columns, CAST(CASE WHEN value LIKE ''GWP%'' THEN REPLACE(value,''GWP '', '''') WHEN value LIKE ''LR%'' THEN REPLACE(value,''LR '', '''') END AS INT) AS Year, CASE WHEN value LIKE ''GWP%'' THEN ''GWP'' WHEN value LIKE ''LR%'' THEN ''LR'' END AS Metrics FROM Unpivoted';
如果发现很难手动为所有列编写类型转换,则可以动态生成它并附加它,例如:
DECLARE @colsCasted AS NVARCHAR(MAX); select @colsCasted = STUFF((SELECT distinct ',' + 'CAST(' + QUOTENAME(column_name) + 'AS DECIMAL(10,2)) AS ' + QUOTENAME(column_name) FROM information_schema.columns WHERE table_name = 'Regions' AND COLUMN_NAME <> 'Region' AND COLUMN_NAME <> 'LOB' FOR XML PATH(''), TYPE ).value('.', 'NVARCHAR(MAX)') , 1, 1, '');
然后在动态查询中将该值附加到它:
SELECT @query = 'WITH Unpivoted AS ( SELECT region, lob, columns, value FROM ( SELECT region, lob, ' + @colsCasted + ' FROM Regions ) AS t UNPIVOT ( columns FOR value IN('+ @cols + ') ) AS u ) SELECT region, lob, columns, CAST(CASE WHEN value LIKE ''GWP%'' THEN REPLACE(value,''GWP '', '''') WHEN value LIKE ''LR%'' THEN REPLACE(value,''LR '', '''') END AS INT) AS Year, CASE WHEN value LIKE ''GWP%'' THEN ''GWP'' WHEN value LIKE ''LR%'' THEN ''LR'' END AS Metrics FROM Unpivoted'; EXECUTE(@query);