【问题标题】:SQL Server 2012 Pivot to Count Types of Data?SQL Server 2012 Pivot 来计算数据类型?
【发布时间】:2013-06-04 02:07:34
【问题描述】:

我有一个如下所示的结果集。谁能告诉我如何“旋转”这个,所以

datadate , timestart , timeend , datatype , datacount , datasum
2013-06-03 ,  20:00:00.0000000 ,  21:00:00.0000000 , 10 , 3 , 30
2013-06-03 ,  20:00:00.0000000 , 21:00:00.0000000 , 20 , 3 , 30
2013-06-03 ,  20:00:00.0000000 , 21:00:00.0000000 , 30 , 3 , 30
2013-06-03 ,  19:00:00.0000000 , 20:00:00.0000000 , 10 , 2 , 20

可以变成这个

date  ,  timestart   timeend   , type10count , type10sum , type20count , type20sum , type30count , type30sum
2013-06-03 , 20:00:00.0000000 , 21:00:00.0000000 , 3 , 30 , 3 , 30 , 3 , 30
2013-06-03 , 19:00:00.0000000 , 20:00:00.0000000 , 2 , 20 , 0 , 0 , 0 , 0

我试图创建一个 PIVOT 以避免 CASE 语句并重新定义一个新表,但我做不到。 这应该怎么做?

    declare @starttable table
    (
    datadate date , timestart time , timeend time , datatype tinyint , datacount int , datasum int
    )
    insert into @starttable  
    select '2013-06-03' , '20:00:00' , '21:00:00' , 10 , 3 , 30
    union all
    select '2013-06-03' , '20:00:00' , '21:00:00' , 20 , 3 , 30
    union all
    select '2013-06-03' , '20:00:00' , '21:00:00' , 30 , 3 , 30
    union all
    select '2013-06-03' , '19:00:00' , '20:00:00' , 10 , 2 , 20

    select datadate , timestart , timeend 
    from ( select datadate , timestart , timeend , datacount ,datasum from @starttable ) as t1
    pivot ( sum(datasum) for datatype in (datacount,datasum) ) as t2
-- yes i know sql server gongs this

【问题讨论】:

    标签: sql sql-server pivot sql-server-2012


    【解决方案1】:

    以下是有效的枢轴语法:

    select datadate, timestart, timeend, [10], [20], [30]
    from ( select datadate , timestart, timeend, datatype, datacount, datasum
           from @starttable
         ) t1
    pivot (sum(datasum) for [datatype] in ([10], [20], [30])
          ) t2;
    

    您需要的第一件事是内部子查询中的datatype。第二件事是数据透视语句中的值列表。

    要在同一查询中同时获取计数和总和,您需要“对齐”数据:

    select datadate, timestart, timeend, [10sum], [10count], [20count], [20sum], [30count], [30sum]
    from (select datadate, timestart, timeend, cast(datatype as varchar(255))+'count' as datatype, datacount as thedata
          from starttable
          union all
          select datadate, timestart, timeend, cast(datatype as varchar(255))+'sum' as datatype, datasum as thedata
          from starttable
         ) t
    pivot (sum(thedata) for [datatype] in ([10sum], [10count], [20count], [20sum], [30count], [30sum])
          ) t2
    

    【讨论】:

      【解决方案2】:

      为了获得您想要的结果,您必须先查看取消透视 datacountdatasum 列,然后应用透视函数。

      数据的反透视将采用多列并返回多行,这将允许使用datatype 值更轻松地进行数据轮换。由于您使用的是 SQL Server 2012,因此您可以使用 UNPIVOT 函数轻松取消透视数据,也可以将 CROSS APPLY 与 VALUES 子句一起使用。

      select t.datadate, t.timestart, t.timeend, 
        'type'+cast(t.datatype as varchar(2))+ replace(c.col, 'data', '') as col, c.value
      from starttable t
      cross apply
      (
        values ('datacount', datacount), ('datasum', datasum)
      ) c (col, value);
      

      Demo。这将给出一个包含多个列的结果,并且它还有一个新的计算列,其中包含将被透视的值:

      |   DATADATE |        TIMESTART |          TIMEEND |         COL | VALUE |
      --------------------------------------------------------------------------
      | 2013-06-03 | 20:00:00.0000000 | 21:00:00.0000000 | type10count |     3 |
      | 2013-06-03 | 20:00:00.0000000 | 21:00:00.0000000 |   type10sum |    30 |
      | 2013-06-03 | 20:00:00.0000000 | 21:00:00.0000000 | type20count |     3 |
      | 2013-06-03 | 20:00:00.0000000 | 21:00:00.0000000 |   type20sum |    30 |
      

      然后你对这个结果应用 PIVOT:

      select datadate, timestart, timeend, 
        type10count, type10sum, type20count, type20sum, type30count, type30sum
      from
      (
        select t.datadate, t.timestart, t.timeend, 
          'type'+cast(t.datatype as varchar(2))+ replace(c.col, 'data', '') as col, c.value
        from starttable t
        cross apply
        (
          values ('datacount', datacount), ('datasum', datasum)
        ) c (col, value)
      ) d
      pivot
      (
        sum(value)
        for col in (type10count, type10sum, type20count, type20sum, type30count, type30sum)
      ) piv;
      

      SQL Fiddle with Demo

      现在,如果您有未知数量的 datatype 值,那么您可以使用动态 SQL 来获取结果:

      DECLARE @cols AS NVARCHAR(MAX),
          @colsNull AS NVARCHAR(MAX),
          @query  AS NVARCHAR(MAX)
      
      select @cols = STUFF((SELECT ',' + QUOTENAME('type'+cast(t.datatype as varchar(2))+c.col) 
                          from starttable t
                          cross apply
                          (
                            values ('count', 1), ('sum', 2)
                          ) c (col, so)
                          group by t.datatype, c.col, c.so
                          order by t.datatype, c.so
                  FOR XML PATH(''), TYPE
                  ).value('.', 'NVARCHAR(MAX)') 
              ,1,1,'')
      
      select @colsNull = STUFF((SELECT ',isNull(' + QUOTENAME('type'+cast(t.datatype as varchar(2))+c.col) 
                                            +', 0) as '+QUOTENAME('type'+cast(t.datatype as varchar(2))+c.col) 
                          from starttable t
                          cross apply
                          (
                            values ('count', 1), ('sum', 2)
                          ) c (col, so)
                          group by t.datatype, c.col, c.so
                          order by t.datatype, c.so
                  FOR XML PATH(''), TYPE
                  ).value('.', 'NVARCHAR(MAX)') 
              ,1,1,'')
      
      set @query = 'SELECT datadate, timestart, timeend,' + @colsNull + ' 
                   from
                  (
                    select t.datadate, t.timestart, t.timeend, 
                      ''type''+cast(t.datatype as varchar(2))+ replace(c.col, ''data'', '''') as col, c.value
                    from starttable t
                    cross apply
                    (
                      values (''datacount'', datacount), (''datasum'', datasum)
                    ) c (col, value)
                  ) d
                  pivot 
                  (
                      max(value)
                      for col in (' + @cols + ')
                  ) p '
      
      execute(@query);
      

      SQL Fiddle with Demo。两个版本都给出了结果:

      |   DATADATE |        TIMESTART |          TIMEEND | TYPE10COUNT | TYPE10SUM | TYPE20COUNT | TYPE20SUM | TYPE30COUNT | TYPE30SUM |
      ----------------------------------------------------------------------------------------------------------------------------------
      | 2013-06-03 | 19:00:00.0000000 | 20:00:00.0000000 |           2 |        20 |           0 |         0 |           0 |         0 |
      | 2013-06-03 | 20:00:00.0000000 | 21:00:00.0000000 |           3 |        30 |           3 |        30 |           3 |        30 |
      

      【讨论】:

      • 我需要一种方法来给出这个答案以及前一个答案的接受答案复选标记。在过去的 12 个小时里,我从两个回复中学到了很多东西。谢谢!
      猜你喜欢
      • 2014-03-20
      • 1970-01-01
      • 1970-01-01
      • 2016-05-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-03-24
      • 1970-01-01
      相关资源
      最近更新 更多