具有列标题的多列到单列?

时间:2014-06-30 06:22:45

标签: sql sql-server sql-server-2005 pivot-table unpivot

我有如下表格。   临时表:

+---------+------+--------+------+
|   Id    | I1   | I2     | I3   | 
+---------+------+--------+------+
|    1    | x1   | 1      |  2   |
|    2    | C    | A      |  B   |
|    3    | x7   | x8     |  X9  |
+---------+------+--------+------+

我正在使用以下查询来透视此表:

select    ID
,value
from dbo.Staging
unpivot
(
  value
  for col in (I1, I2,I3 )     
) un

我想从登台表中获取“列标题名称”,如下所示。我怎么能这样做?

+-------+-------+-------------------------+
| value | ID    |  Column header name     |
+-------+-------+-------------------------+
|  x1   |  1    |       I1                |
|  1    |  1    |       I2                |
|  2    |  1    |       I3                |
|  C    |  2    |       I1                |
|  A    |  2    |       I2                |
|  B    |  2    |       I3                | 
|  x7   |  3    |       I1                |
|  x8   |  3    |       I2                | 
|  x9   |  3    |       I3                |
+-------+-------+-------------------------+

2 个答案:

答案 0 :(得分:2)

假设您有预先知道的固定数量的列(在本例中为3),并且所有值都是非空的,您可以将列名硬编码到输出中,如下所示:

;with cte as
 (select 
  ID,
  value,
  row_number() over (partition by id order by value) rn
  from dbo.Staging
  unpivot
  (
   value
   for col in (I1, I2,I3 )     
  ) un
 )

 select 
 id, 
 value, 
 case when rn = 1 then 'I1' when rn = 2 then 'I2' else 'I3' end as 'Column header name'
 from cte

编辑:由于值可能始终不是有序的,我们可以在ID子句中使用ORDER BYOVER。这实际上是为排序传递的虚拟值,因此它将始终按原样返回数据,而不进行实际排序。

答案 1 :(得分:2)

我永远不会记得UNPIVOT语法和限制所以我使用CROSS APPLY VALUES

SELECT Id
      ,Value
      ,ColumnName
FROM dbo.Staging
     CROSS APPLY (
         VALUES (I1, 'I1')
               ,(I2, 'I2')
               ,(I3, 'I3')
     ) AS CA1(Value, ColumnName)