簡體   English   中英

SQL Server 2008:在多個列上進行數據透視

[英]SQL Server 2008 : pivoting on multiple columns

在SQL Server 2008中需要有關數據透視子句的幫助。我有一個包含此信息的表:

我有一個包含9列的表: IDPeriod_1Period_4作為日期(即2013-04、2013-07等)和Amount_1Amount_4 (即30,40等)。 我想從所有不同日期Period_1Period_4支點作為列名,然后Amount_1對應Period_1Amount_2對應Period_2Amount_3對應Period_3Amount_4對應Period_4作為行值。

這是我目前想出的T-SQL:

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

SELECT @cols = STUFF((
        SELECT DISTINCT ',' + QUOTENAME(ans)
        FROM (
            SELECT Period_1 AS ans
            FROM Booking

            UNION

            SELECT Period_2 AS ans
            FROM Booking

            UNION

            SELECT Period_3 AS ans
            FROM Booking

            UNION

            SELECT Period_4 AS ans
            FROM Booking
            ) a
        FOR XML PATH('')
            ,TYPE
        ).value('.', 'NVARCHAR(MAX)'), 1, 1, '')

SET @query = 'SELECT Id ' + @cols + ' from 
         (
            select Id, Period_1, Amount_1, Period_2, Amount_2
            from Booking
         ) x
        pivot 
        (
            max(Amount_1)
            for Period_1 in (' + @cols + ')

        ) p 
(
            max(Amount_2)
            for Period_2 in (' + @cols + ')

        ) p

        '

EXECUTE (@query)

我得到錯誤:

消息265,第16層,狀態1,第18行
PIVOT運算符中指定的列名稱“ 2013-10”與PIVOT參數中的現有列名稱沖突。

有什么辦法可以對包含相同值的多個列進行數據透視查詢嗎? 請寫一個響應示例。

我對此表示感謝。 提前致謝。

問題的一部分是您的數據沒有被規范化,因為具有包含Period_1Amount_1Period_2Amount_2等的列使查詢數據變得異常困難。 我的第一個建議是考慮將您的表結構固定為類似於以下內容的內容:

create table booking
(
  id int,
  period datetime,
  amount decimal(10, 5)
);

這樣您可以為每個ID設置多個期間和金額。 還有其他設計方法,但這應該可以使您了解如何修復當前結構。

如果您無法修復您的結構,那么我建議您先將UNPIVOT,然后再將PIVOT應用於現有表。 UNPIVOT會將多列數據轉換為多行,然后您可以將PIVOT應用於金額以得到最終結果。

UNPIVOT的基本語法如下。 我將CROSS APPLY與UNION ALL結合使用,因為我們需要同時取消指定期間和金額:

select id, 
  convert(varchar(7), period, 120) period,
  amount
from
(
  select id, 
    period_1, period_2, period_3, period_4,
    amount_1, amount_2, amount_3, amount_4
  from booking
) d
cross apply
(
  select period_1, amount_1 union all
  select period_2, amount_2 union all
  select period_3, amount_3 union all
  select period_4, amount_4
) c (period, amount);

請參閱帶有演示的SQL Fiddle 這樣可以為您提供以下格式的數據:

| ID |  PERIOD | AMOUNT |
-------------------------
|  1 | 2013-01 |     30 |
|  1 | 2013-04 |     40 |
|  1 | 2013-07 |     50 |
|  1 | 2013-10 |     60 |

一旦數據采用這種格式,就可以將PIVOT函數應用於“ Period列中的值:

select id,
  [2013-01], [2013-04], [2013-05],
  [2013-07], [2013-08], [2013-10],
  [2013-11]
from
(
  select id, 
    convert(varchar(7), period, 120) period,
    amount
  from
  (
    select id, 
      period_1, period_2, period_3, period_4,
      amount_1, amount_2, amount_3, amount_4
    from booking
  ) d
  cross apply
  (
    select period_1, amount_1 union all
    select period_2, amount_2 union all
    select period_3, amount_3 union all
    select period_4, amount_4
  ) c (period, amount)
) src
pivot
(
  sum(amount)
  for period in ([2013-01], [2013-04], [2013-05],
                 [2013-07], [2013-08], [2013-10],
                 [2013-11])
) piv;

請參閱帶有演示的SQL Fiddle 當然,如果您提前知道這些值,上述方法將非常有用。 但是如果您不這樣做,那么您將需要考慮使用動態SQL來獲得結果:

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

select @cols = STUFF((SELECT ',' + QUOTENAME(period) 
                    from 
                    (
                      select convert(varchar(7), period_1, 120) period, period_1 dt 
                      from booking union all
                      select convert(varchar(7), period_2, 120) period, period_2 dt
                      from booking union all
                      select convert(varchar(7), period_3, 120) period, period_3 dt
                      from booking union all
                      select convert(varchar(7), period_4, 120) period, period_4
                      from booking
                    ) d
                    group by period, dt
                    order by dt
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')

set @query = 'SELECT id, ' + @cols + ' 
            from
            (
              select id, 
                convert(varchar(7), period, 120) period,
                amount
              from
              (
                select id, 
                  period_1, period_2, period_3, period_4,
                  amount_1, amount_2, amount_3, amount_4
                from booking
              ) d
              cross apply
              (
                select period_1, amount_1 union all
                select period_2, amount_2 union all
                select period_3, amount_3 union all
                select period_4, amount_4
              ) c (period, amount)
            ) src
            pivot 
            (
                sum(amount)
                for period in (' + @cols + ')
            ) p '

execute(@query);

請參閱帶有演示的SQL Fiddle 這些查詢將產生類似於以下內容的結果:

| ID | 2013-01 | 2013-04 | 2013-05 | 2013-07 | 2013-08 | 2013-10 | 2013-11 |
----------------------------------------------------------------------------
|  1 |     105 |      40 |      86 |      50 |     120 |      60 |      65 |

我認為您必須在字段名稱后添加一些內容,並為每個使用的值創建一個@cols變量,即:

SELECT @cols1 = STUFF((
        SELECT DISTINCT ',' + QUOTENAME(ans)
        FROM (SELECT '1_'+CAST(Period_1  AS VARCHAR(12)) AS ans
              FROM #test
              UNION
              SELECT '1_'+CAST(Period_2  AS VARCHAR(12)) AS ans
              FROM #test
            ) a
        FOR XML PATH(''),TYPE).value('.', 'NVARCHAR(MAX)'), 1, 1,'')
        ,@cols2 = STUFF((
                SELECT DISTINCT ',' + QUOTENAME(ans)
                FROM (SELECT '2_'+CAST(Period_1 AS VARCHAR(12)) AS ans
                      FROM #test
                      UNION
                      SELECT '2_'+CAST(Period_2 AS VARCHAR(12)) AS ans
                      FROM #test
                    ) a
                FOR XML PATH(''),TYPE).value('.', 'NVARCHAR(MAX)'), 1, 1,'')

然后在旋轉時引用適當的變量,您也必須在其中添加字段名稱:

(
    max(Amount_1)
    for '1_'+CAST(Period_1 AS VARCHAR(12)) in (' + @cols1 + ')

) p 

可能有一種更聰明的方法來執行此操作,但我不知道有一種方法。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM