我有一个包含PROJECTNAME,ACTUALCOST,PROJECTSTART和PROJECTEND列的表格,如下所示:
PROJECTNAME ACTUAL COST PROJECTSTART PROJECTEND
abc 1500 2011-12-01 2012-07-31
prj1 1170 2012-01-09 2012-06-30
xyz 5350 2012-01-30 2012-03-30
我想获得如下输出:
PRJNAME DEC11 JAN12 FEB12 MAR12 APR12 MAY12 JUN12 JUL12 ...
abc 187.5 187.5 187.5 187.5 187.5 187.5 187.5 187.5
prj1 117 195 195 195 195 195
我需要每个项目名称的每月费用细分,具体取决于每个月剩余的天数。
答案 0 :(得分:1)
您可以使用PIVOT
功能获取结果。
我建议这样做的方法是首先编写一个硬编码版本,然后将其转换为动态sql。
注意:我通过将Actual Cost
除以projectstart / projectend之间的天数来确定每月的费用。这至少应该让您开始实际报告。
静态版本与此类似:
;with cte as
(
select projectname, [ACTUAL COST], [PROJECTSTART], [PROJECTEND]
from yourtable
union all
select projectname, [ACTUAL COST],
dateadd(d, 1, PROJECTSTART),
PROJECTEND
from cte
where dateadd(d, 1, PROJECTSTART) <= ProjectEnd
)
select *
from
(
select
my.projectname,
my.monthyear,
my.totaldayspermonth * a.perdaycost AmountPerMonth
from
(
select projectname,
left(datename(m, projectstart), 3) + cast(year(projectstart) as varchar(4)) monthyear,
count(*) TotalDaysPerMonth
from cte
group by projectname,
[actual cost],
left(datename(m, projectstart), 3) + cast(year(projectstart) as varchar(4))
) my
cross apply
(
select projectname,
round([actual cost] / (datediff(d, projectstart, projectend) *1.0), 2) PerDayCost
from yourtable a
where my.projectname = a.projectname
) a
) src
pivot
(
max(AMOUNTPERMONTH)
for monthyear in (Dec2011, Jan2012, Feb2012, Mar2012,
Apr2012, May2012, Jun2012, Jul2012, Aug2012)
) piv
OPTION(MAXRECURSION 0);
一旦拥有静态版本,就可以更轻松地将其转换为动态SQL。动态SQL将是:
;with cte as
(
select projectname, [ACTUAL COST], [PROJECTSTART], [PROJECTEND]
from yourtable
union all
select projectname, [ACTUAL COST],
dateadd(d, 1, PROJECTSTART),
PROJECTEND
from cte
where dateadd(d, 1, PROJECTSTART) <= ProjectEnd
)
select *
into #dates
from cte
OPTION(MAXRECURSION 0)
DECLARE @cols AS NVARCHAR(MAX),
@query AS NVARCHAR(MAX)
select @cols = STUFF((SELECT ',' + QUOTENAME(left(datename(m, projectstart), 3) + cast(year(projectstart) as varchar(4)))
from #dates
group by datename(m, projectstart), year(projectstart), month(projectstart)
order by year(projectstart), month(projectstart)
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set @query = ';with cte as
(
select projectname, [ACTUAL COST], [PROJECTSTART], [PROJECTEND]
from yourtable
union all
select projectname, [ACTUAL COST],
dateadd(d, 1, PROJECTSTART),
PROJECTEND
from cte
where dateadd(d, 1, PROJECTSTART) <= ProjectEnd
)
select projectname, '+@cols+'
from
(
select
my.projectname,
my.monthyear,
my.totaldayspermonth * a.perdaycost AmountPerMonth
from
(
select projectname,
left(datename(m, projectstart), 3) + cast(year(projectstart) as varchar(4)) monthyear,
count(*) TotalDaysPerMonth
from cte
group by projectname,
[actual cost],
left(datename(m, projectstart), 3) + cast(year(projectstart) as varchar(4))
) my
cross apply
(
select projectname,
round([actual cost] / (datediff(d, projectstart, projectend) *1.0), 2) PerDayCost
from yourtable a
where my.projectname = a.projectname
) a
) src
pivot
(
max(AMOUNTPERMONTH)
for monthyear in ('+@cols+')
)piv
OPTION(MAXRECURSION 0)'
execute(@query)
两个查询的结果是:
| PROJECTNAME | DEC2011 | JAN2012 | FEB2012 | MAR2012 | APR2012 | MAY2012 | JUN2012 | JUL2012 |
-----------------------------------------------------------------------------------------------
| abc | 191.27 | 191.27 | 178.93 | 191.27 | 185.1 | 191.27 | 185.1 | 191.27 |
| prj1 | (null) | 155.48 | 196.04 | 209.56 | 202.8 | 209.56 | 202.8 | (null) |
| xyz | (null) | 178.34 | 2585.93 | 2675.1 | (null) | (null) | (null) | (null) |