我有一个非常艰难的时刻试图找出如何在具有多个列的sql Server 2008中进行动态枢轴.
我的样品表如下:
- ID YEAR TYPE TOTAL VOLUME
- DD1 2008 A 1000 10
- DD1 2008 B 2000 20
- DD1 2008 C 3000 30
- DD1 2009 A 4000 40
- DD1 2009 B 5000 50
- DD1 2009 C 6000 60
- DD2 2008 A 7000 70
- DD2 2008 B 8000 80
- DD2 2008 C 9000 90
- DD2 2009 A 10000 100
- DD2 2009 B 11000 110
- DD2 2009 C 12000 120
我正在尝试如下的枢纽:
- ID 2008_A_TOTAL 2008_A_VOLUME 2008_B_TOTAL 2008_B_VOLUME 2008_C_TOTAL 2008_C_VOLUME 2009_A_TOTAL 2009_A_VOLUME 2009_B_TOTAL 2009_B_VOLUME 2009_C_TOTAL 2009_C_VOLUME
- DD1 1000 10 2000 20 3000 30 4000 40 5000 50 6000 60
- DD2 7000 70 8000 80 9000 90 10000 100 11000 110 12000 120
- CREATE TABLE ATM_TRANSACTIONS
- (
- ID varchar(5),T_YEAR varchar(4),T_TYPE varchar(3),TOTAL int,VOLUME int
- );
- INSERT INTO ATM_TRANSACTIONS
- (ID,T_YEAR,T_TYPE,TOTAL,VOLUME)
- VALUES
- ('DD1','2008','A',1000,10),('DD1','B',2000,20),'C',3000,30),'2009',4000,40),5000,50),6000,60),('DD2',7000,70),8000,80),9000,90),10000,100),11000,110),1200,120);
T_Year列可能会在将来更改,但T_TYPE列通常是知道的,所以我不知道我是否可以使用sql Server中的PIVOT函数与动态代码的组合?
我试着按照这里的例子:
但我最终得到了奇怪的结果.
解决方法
为了获得结果,您需要先查看“总量”和“体积”列中的数据,然后再应用PIVOT函数才能获得最终结果.我的建议是首先写一个硬编码版本的查询,然后将其转换为动态sql.
UNPIVOT进程将这些多列转换成行.有几种方法可以使用UNPIVOT,您可以使用UNPIVOT功能,也可以使用CROSS APPLY.不透明数据的代码将类似于:
- select id,col = cast(t_year as varchar(4))+'_'+t_type+'_'+col,value
- from ATM_TRANSACTIONS t
- cross apply
- (
- select 'total',total union all
- select 'volume',volume
- ) c (col,value);
这给你的数据格式如下:
- +-----+---------------+-------+
- | id | col | value |
- +-----+---------------+-------+
- | DD1 | 2008_A_total | 1000 |
- | DD1 | 2008_A_volume | 10 |
- | DD1 | 2008_B_total | 2000 |
- | DD1 | 2008_B_volume | 20 |
- | DD1 | 2008_C_total | 3000 |
- | DD1 | 2008_C_volume | 30 |
- +-----+---------------+-------+
然后你可以应用PIVOT功能:
- select ID,[2008_A_total],[2008_A_volume],[2008_B_total],[2008_B_volume],[2008_C_total],[2008_C_volume],[2009_A_total],[2009_A_volume]
- from
- (
- select id,value
- from ATM_TRANSACTIONS t
- cross apply
- (
- select 'total',total union all
- select 'volume',volume
- ) c (col,value)
- ) d
- pivot
- (
- max(value)
- for col in ([2008_A_total],[2009_A_volume])
- ) piv;
现在您具有正确的逻辑,您可以将其转换为动态sql:
- DECLARE @cols AS NVARCHAR(MAX),@query AS NVARCHAR(MAX)
- select @cols = STUFF((SELECT ',' + QUOTENAME(cast(t_year as varchar(4))+'_'+t_type+'_'+col)
- from ATM_TRANSACTIONS t
- cross apply
- (
- select 'total',1 union all
- select 'volume',2
- ) c (col,so)
- group by col,so,T_YEAR
- order by T_YEAR,so
- FOR XML PATH(''),TYPE
- ).value('.','NVARCHAR(MAX)'),1,'')
- set @query = 'SELECT id,' + @cols + '
- from
- (
- select id,col = cast(t_year as varchar(4))+''_''+t_type+''_''+col,value
- from ATM_TRANSACTIONS t
- cross apply
- (
- select ''total'',total union all
- select ''volume'',volume
- ) c (col,value)
- ) x
- pivot
- (
- max(value)
- for col in (' + @cols + ')
- ) p '
- execute sp_executesql @query;
这将给你一个结果:
- +-----+--------------+---------------+--------------+---------------+--------------+---------------+--------------+---------------+--------------+---------------+--------------+---------------+
- | id | 2008_A_total | 2008_A_volume | 2008_B_total | 2008_B_volume | 2008_C_total | 2008_C_volume | 2009_A_total | 2009_A_volume | 2009_B_total | 2009_B_volume | 2009_C_total | 2009_C_volume |
- +-----+--------------+---------------+--------------+---------------+--------------+---------------+--------------+---------------+--------------+---------------+--------------+---------------+
- | DD1 | 1000 | 10 | 2000 | 20 | 3000 | 30 | 4000 | 40 | 5000 | 50 | 6000 | 60 |
- | DD2 | 7000 | 70 | 8000 | 80 | 9000 | 90 | 10000 | 100 | 11000 | 110 | 1200 | 120 |
- +-----+--------------+---------------+--------------+---------------+--------------+---------------+--------------+---------------+--------------+---------------+--------------+---------------+