0

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

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
4

2 回答 2

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
于 2013-06-04T02:24:03.653 回答
1

为了获得您想要的结果,您必须首先查看取消旋转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);

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

|   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

现在,如果您有未知数量的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 |
于 2013-06-04T02:41:50.087 回答