需要SQL Server 2008中的pivot子句的帮助。我有一个包含此信息的表:
我有一个包含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)
我得到了错误:
Msg 265,Level 16,State 1,Line 18
PIVOT运算符中指定的列名“2013-10”与PIVOT参数中的现有列名冲突。
有没有办法对包含相同值的多个列进行数据透视查询?请写一个关于如何做的回答。
我很感激这方面的任何帮助。提前致谢。
答案 0 :(得分:3)
您的部分问题是您的数据未规范化,包含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,因为我们需要同时忽略Period和Amount:
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 with demo。这将为您提供以下格式的数据:
| 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 with Demo。当然,如果您提前了解价值,上述内容将会很有效。但是,如果不这样做,那么您将需要使用动态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 with Demo。这些查询将得到类似于:
的结果| ID | 2013-01 | 2013-04 | 2013-05 | 2013-07 | 2013-08 | 2013-10 | 2013-11 |
----------------------------------------------------------------------------
| 1 | 105 | 40 | 86 | 50 | 120 | 60 | 65 |
答案 1 :(得分:0)
我认为您必须在字段名称后附加内容,并为您正在使用的每个值创建一个@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
可能有更聪明的方法可以做到这一点,但我不知道。