【问题标题】:T-SQL: from rows to columns but not an actual pivotT-SQL:从行到列,但不是实际的枢轴
【发布时间】:2012-12-05 16:39:28
【问题描述】:

是否有 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 |
+-------------------------+---------+--------+---------+--------+---------+--------+

【问题讨论】:

  • 对于结果中的最后两列,您的意思是在名称前加上6 还是应该是1?您知道要转换的所有 idDevices 还是未知?

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


【解决方案1】:

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

首先,您执行UNPIVOT,它将您当前的多个列转换为两列——一列带有值,另一列带有列名。 UNPIVOT 的关键是数据类型相同,所以在子查询中我 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 |

完成反透视后,即可应用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

【讨论】:

  • 您的回答非常好。我需要进一步的步骤:在公式中使用列。示例:1_M300 + 3_M300 + 6_300(+ 是 SUM 而不是串联)。
猜你喜欢
  • 2013-06-01
  • 2012-09-23
  • 2011-02-24
  • 2011-04-26
  • 2017-12-12
  • 2016-05-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多