T-SQL:从行到列但不是实际的数据透视表

时间:2012-12-05 16:39:28

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

是否有T-SQL(SQL Server 2008R2)查询将TABLE_1转换为预期的结果集?

TABLE_1

+----------+-------------------------+---------+------+
| IdDevice | Timestamp               | M300    | M400 |
+----------+-------------------------+---------+------+
| 3        | 2012-12-05 16:29:51.000 | 2357,69 | 520  |
| 6        | 2012-12-05 16:29:51.000 | 1694,81 | 470  |
| 1        | 2012-12-05 16:29:51.000 | 2046,33 | 111  |
+----------+-------------------------+---------+------+

预期结果集

+-------------------------+---------+--------+---------+--------+---------+--------+
|        Timestamp        | 3_M300  | 3_M400 | 6_M300  | 6_M400 | 6_M300  | 6_M400 |
+-------------------------+---------+--------+---------+--------+---------+--------+
| 2012-12-05 16:29:51.000 | 2357,69 |    520 | 1694,81 |    470 | 2046,33 |    111 |
+-------------------------+---------+--------+---------+--------+---------+--------+

1 个答案:

答案 0 :(得分:2)

这仍然是PIVOT查询,但在PIVOT之前,您必须执行UNPIVOT个列。

首先,执行获取当前多列的UNPIVOT并将它们转换为两列 - 一列具有值,另一列具有列名称。 UNPIVOT的关键是数据类型相同,因此在子查询I cast中,任何列都使用相同的数据类型:

select timestamp,
    value, cast(iddevice as varchar(10)) + '_'+col as col
  from
  (
    select iddevice,
      timestamp,
      cast(m300 as varchar(10)) m300,
      cast(m400 as varchar(10)) m400
    from yourtable
  ) src
  unpivot
  (
    value
    for col in (m300, m400)
  ) unpiv

请参阅SQL Fiddle with Demo

结果:

|                       TIMESTAMP |   VALUE |    COL |
------------------------------------------------------
| December, 05 2012 16:29:51+0000 | 2357,69 | 3_m300 |
| December, 05 2012 16:29:51+0000 |     520 | 3_m400 |
| December, 05 2012 16:29:51+0000 | 1694,81 | 6_m300 |
| December, 05 2012 16:29:51+0000 |     470 | 6_m400 |
| December, 05 2012 16:29:51+0000 | 2046,33 | 1_m300 |
| December, 05 2012 16:29:51+0000 |     111 | 1_m400 |

完成unpivot后,您可以应用PIVOT功能:

select *
from
(
  select timestamp,
    value, cast(iddevice as varchar(10)) + '_'+col as col
  from
  (
    select iddevice,
      timestamp,
      cast(m300 as varchar(10)) m300,
      cast(m400 as varchar(10)) m400
    from yourtable
  ) src
  unpivot
  (
    value
    for col in (m300, m400)
  ) unpiv
) src1
pivot
(
  max(value)
  for col in ([3_m300], [3_m400],
              [6_m300], [6_m400],
              [1_m300], [1_m400])
) piv

请参阅SQL Fiddle with Demo

结果:

|                       TIMESTAMP |  3_M300 | 3_M400 |  6_M300 | 6_M400 |  1_M300 | 1_M400 |
--------------------------------------------------------------------------------------------
| December, 05 2012 16:29:51+0000 | 2357,69 |    520 | 1694,81 |    470 | 2046,33 |    111 |

如果您要将未知数量的IdDevices转换为列,则可以使用动态SQL:

DECLARE @cols AS NVARCHAR(MAX),
    @query  AS NVARCHAR(MAX)

select @cols = STUFF((SELECT DISTINCT ',' 
                      + quotename(cast(t.IdDevice as varchar(10)) +'_'
                                  +c.name)
                    from yourtable t
                     cross apply sys.columns as C
                   where C.object_id = object_id('yourtable') and
                         C.name not in ('IdDevice', 'Timestamp')
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')


set @query = 'SELECT timestamp,' + @cols + ' from 
             (
               select timestamp,
                value, cast(iddevice as varchar(10)) + ''_''+col as col
              from
              (
                select iddevice,
                  timestamp,
                  cast(m300 as varchar(10)) m300,
                  cast(m400 as varchar(10)) m400
                from yourtable
              ) src
              unpivot
              (
                value
                for col in (m300, m400)
              ) unpiv
            ) x
            pivot
            (
              max(value)
              for col in (' + @cols + ')
            ) p '

execute(@query)

请参阅SQL Fiddle with Demo

编辑,如果您需要每个m值的总计字段,则可以使用:

select timestamp,
  [3_m300], [3_m400],
  [6_m300], [6_m400],
  [1_m300], [1_m400],
  [1_m300] + [3_m300] + [6_m300] Total_m300,
  [1_m400] + [3_m400] + [6_m400] Total_m400
from
(
  select timestamp,
    value, cast(iddevice as varchar(10)) + '_'+col as col
  from
  (
    select iddevice,
      timestamp,
      m300,
      m400
    from yourtable
  ) src
  unpivot
  (
    value
    for col in (m300, m400)
  ) unpiv
) src1
pivot
(
  sum(value)
  for col in ([3_m300], [3_m400],
              [6_m300], [6_m400],
              [1_m300], [1_m400])
) piv

请参阅SQL Fiddle with Demo