2013-06-04 71 views
0

我有一個如下所示的結果集。誰能告訴我如何「轉動」這一點,所以SQL Server 2012透視計算數據類型?

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 

我試圖讓樞軸,以避免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 

回答

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。第二件事是pivot語句中的值列表。

兩者都要計數,並在同一個查詢的總和,你需要「對齊」的數據:

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 
1

爲了得到你想要你就不得不看unpivoting的結果首先使用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 | 
+0

我需要一種方法來給出這個答案以及前一個答案的答案複選標記。在兩個回覆中,我在過去12小時內學到了很多。謝謝! – Snowy