[英]SQL Server 2008 : pivoting on multiple columns
在SQL Server 2008中需要有關數據透視子句的幫助。我有一個包含此信息的表:
我有一個包含9列的表: ID
, Period_1
到Period_4
作為日期(即2013-04、2013-07等)和Amount_1
到Amount_4
(即30,40等)。 我想從所有不同日期Period_1
到Period_4
支點作為列名,然后Amount_1
對應Period_1
, Amount_2
對應Period_2
, Amount_3
對應Period_3
和Amount_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_1
, Amount_1
, Period_2
, Amount_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.