sql server - 动态数据透视表和计算列

时间:2014-01-06 17:32:42

标签: sql-server pivot dynamic-pivot

我正在寻找帮助从以下(缩写)源表中生成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枢轴,我一直在讨论很多问题/答案,但由于我在这方面的背景有限,我没有找到任何我能适应的需求。

1 个答案:

答案 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 |