0

我正在寻求帮助,在 SQL Server 中从以下(缩写)源表生成包含动态列和计算值的表:

分配源表

名称 StartDate EndDate 值因素
吉姆 2013-08-01 2013-09-06 200.0 0.5
鲍勃 2013-07-27 2013-11-01 140.0 1.0
爱丽丝 2013-08-29 2014-03-22 200.0 0.8
吉姆 2013-08-20 2013-09-01 250.0 0.5

报告周源表

周末结束日期
2013-08-18
2013-08-25
2013-09-01
2013-09-08

期望结果表

名称 StartDate EndDate 值因子 2013-08-18 2013-08-25 2013-09-01 2013-09-08
吉姆 2013-08-01 2013-09-06 200.0 0.5 100.0 100.0 100.0 0.0
鲍勃 2013-07-27 2013-11-01 140.0 1.0 140.0 140.0 140.0 140.0
爱丽丝 2013-08-29 2014-03-22 200.0 0.8 0.0 0.0 160.0 160.0
吉姆 2013-08-20 2013-09-01 250.0 0.5 0.0 125.0 125.0 0.0

基本上,我需要将报告行表转换为列,然后计算透视列日期(报告周/周结束日期)在 StartDate 和 EndDate 之间的值。如果日期超出该范围,则该值应设置为零。“报告周数”表可以随时间变化,并且可以从另一个查询生成。StartDate 和 EndDate 通常与 WeekEndDate 不匹配。我一直在研究很多关于动态 sql 枢轴的问题/答案,但鉴于我在该领域的有限背景,我还没有找到任何可以适应需求的东西。

4

1 回答 1

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 |
于 2014-01-06T17:55:30.637 回答