如何使用两个值(列)进行PIVOT查询?

时间:2018-01-19 16:29:17

标签: sql sql-server sql-server-2008 tsql pivot

我正在尝试创建两列PIVOT查询。结构如下:

DECLARE @Tmp TABLE(  Id1 int, Id2 int,  Name nvarchar(20), Val1 int, Val2 nvarchar(10))

使用以下虚拟数据:

        INSERT INTO @Tmp VALUES(1,10,'A',2,'str1'), (1,11,'B',2,'str2'),     
(2,10,'A',3,'str3'),(3,11,'B',4, null),(4,11,'B',5,'str4'),(4,10,'A',5,null)

我试图获得的是具有2个不同值(Val1, Val2)的PIVOT查询。我确实尝试了以下查询,但是,由于Val2nvarchar

,因此无法对结果中的值进行分组
     SELECT * FROM 
        (SELECT Id1, Name, Val1, Val2, Name +'_Val2' AS ColVal2  FROM @Tmp) AS tb 
        PIVOT(MIN(Val1) FOR Name IN([A],[B])) pv
        PIVOT(MIN(Val2) FOR ColVal2 IN([A_Val2],[B_Val2])) pv2
        -- GROUP BY could go here ... 

重要的是,查询将是动态的,因为Name中的值不固定,即Id1可能与n Id2相关

所需的输出应如下所示:

Id1     A   B     A_Val2    B_Val2  
 1      2   2       str1    str2  
 2      3   NULL    str3    NULL 
 3   NULL   4       NULL    NULL  
 4      5   5       NULL    str4

任何建议都将不胜感激

1 个答案:

答案 0 :(得分:5)

使用条件聚合

更容易实现
SELECT Id1,
       [A] = Min(CASE WHEN NAME = 'a' THEN Val1 END),
       [B] = Min(CASE WHEN NAME = 'b' THEN Val1 END),
       [A_Val2] = Min(CASE WHEN NAME = 'a' THEN Val2 END),
       [B_Val2] = Min(CASE WHEN NAME = 'b' THEN Val2 END)
FROM   @Tmp
GROUP  BY Id1 

这是一个动态版本(将表变量更改为临时表)

declare @col_list varchar(max) = '',@sql varchar(max)

set @col_list = stuff((select distinct ','+quotename(Name),',' ,quotename(Name+'_Val2') from #Tmp for xml path('')),1,1,'')
--select @col_list
set @sql = '
SELECT *
FROM   (SELECT Id1,
               col,
               val
        FROM   #Tmp
               CROSS apply (VALUES (Cast(Val1 AS VARCHAR(50)),NAME),
                                   (Val2,NAME + ''_Val2'')) cs (val, col))a
       PIVOT (Max(val)
             FOR col IN ('+@col_list+')) pv' 

exec (@sql)