我正在寻找帮助从以下(缩写)源表中生成SQL Server中包含动态列和计算值的表:
作业来源表
Name StartDate EndDate Value Factor Jim 2013-08-01 2013-09-06 200.0 0.5 Bob 2013-07-27 2013-11-01 140.0 1.0 Alice 2013-08-29 2014-03-22 200.0 0.8 Jim 2013-08-20 2013-09-01 250.0 0.5
报告周源表
WeekEndDate 2013-08-18 2013-08-25 2013-09-01 2013-09-08
期望的结果表
Name StartDate EndDate Value Factor 2013-08-18 2013-08-25 2013-09-01 2013-09-08 Jim 2013-08-01 2013-09-06 200.0 0.5 100.0 100.0 100.0 0.0 Bob 2013-07-27 2013-11-01 140.0 1.0 140.0 140.0 140.0 140.0 Alice 2013-08-29 2014-03-22 200.0 0.8 0.0 0.0 160.0 160.0 Jim 2013-08-20 2013-09-01 250.0 0.5 0.0 125.0 125.0 0.0
基本上,我需要将报告行表转换为列,然后计算一个值,其中透视列日期(Reporting Weeks / WeekEndDate)介于StartDate和EndDate之间。如果日期超出该范围,则该值应设置为零。 “报告周”表可以随时间变化,并且可以从另一个查询生成。 StartDate和EndDate通常与WeekEndDate不匹配。关于动态sql枢轴,我一直在讨论很多问题/答案,但由于我在这方面的背景有限,我没有找到任何我能适应的需求。
答案 0 :(得分:0)
在处理动态SQL版本之前,我首先使用您的有限日期将查询编写为静态版本。为了得到结果,我将在子查询中计算您需要的值,然后在weekenddates
上进行转动。
如果您的值有限,则基本语法为:
select name, startdate, enddate,
value, factor,
coalesce([2013-08-18], 0) [2013-08-18],
coalesce([2013-08-25], 0) [2013-08-25],
coalesce([2013-09-01], 0) [2013-09-01],
coalesce([2013-09-08], 0) [2013-09-08]
from
(
select a.name,
a.startdate,
a.enddate,
a.value,
a.factor,
convert(varchar(10), r.weekenddate, 120) weekenddate,
amt = a.value * a.factor
from assignments a
inner join reportingweeks r
on r.weekenddate >= a.startdate
and r.weekenddate <= a.enddate
) d
pivot
(
sum(amt)
for weekenddate in ([2013-08-18], [2013-08-25], [2013-09-01],
[2013-09-08])
) piv;
见SQL Fiddle with Demo。一旦拥有了正确的逻辑,就可以将查询转换为动态SQL:
DECLARE @cols AS NVARCHAR(MAX),
@colsNull AS NVARCHAR(MAX),
@query AS NVARCHAR(MAX)
select @cols = STUFF((SELECT ',' + QUOTENAME(dt)
from
(
select convert(varchar(10), weekenddate, 120) dt
from reportingweeks
) d
group by dt
order by dt
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
select @colsNull = STUFF((SELECT ', coalesce(' + QUOTENAME(dt)+', 0) as '+QUOTENAME(dt)
from
(
select convert(varchar(10), weekenddate, 120) dt
from reportingweeks
) d
group by dt
order by dt
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set @query = 'SELECT name, startdate, enddate,
value, factor, ' + @colsNull + '
from
(
select a.name,
a.startdate,
a.enddate,
a.value,
a.factor,
convert(varchar(10), r.weekenddate, 120) weekenddate,
amt = a.value * a.factor
from assignments a
inner join reportingweeks r
on r.weekenddate >= a.startdate
and r.weekenddate <= a.enddate
) x
pivot
(
sum(amt)
for weekenddate in (' + @cols + ')
) p '
execute sp_executesql @query;
见SQL Fiddle with Demo。两者都会给出结果:
| NAME | STARTDATE | ENDDATE | VALUE | FACTOR | 2013-08-18 | 2013-08-25 | 2013-09-01 | 2013-09-08 |
|-------|------------|------------|-------|--------|------------|------------|------------|------------|
| Alice | 2013-08-29 | 2014-03-22 | 200 | 0.8 | 0 | 0 | 160 | 160 |
| Bob | 2013-07-27 | 2013-11-01 | 140 | 1 | 140 | 140 | 140 | 140 |
| Jim | 2013-08-01 | 2013-09-06 | 200 | 0.5 | 100 | 100 | 100 | 0 |
| Jim | 2013-08-20 | 2013-09-01 | 250 | 0.5 | 0 | 125 | 125 | 0 |