您的部分问题是您的数据未标准化,具有 , , 等的列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 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 |