如何编写SQL来级联累积数据行?

时间:2010-08-10 09:15:52

标签: sql sql-server

我在DB中有一个工作计划如下。例如,第一行意味着A队在6月份有10个小时的工作要做(SP1006)。

Team Sprint  WorkHours
A    1006    10
A    1007    20
A    1008    30
A    1009    40
B    1008    50
B    1009    60
B    1010    70

我想将其推导出以下表格,以显示:根据工作计划,在每个月末,还有多少小时可以完成。如您所见,派生表的字段也取决于原始数据表。

Team    SP1005  SP1006  SP1007  SP1008  SP1009  SP1010
A       100     90      70      40      0       0
B       180     180     180     130     70      0

我正在尝试在SQL Server 2000上执行此操作。这对我来说真的很难。有人可以帮忙吗?非常感谢!

编辑或者你可以忽略行到列的转换部分(我知道该怎么做),只关注积累部分。

2 个答案:

答案 0 :(得分:2)

对于积累部分use a cursor。除非结果集非常小(可能<100行才能处理),否则你可以使用三角形连接。

SELECT t1.Team, t1.Sprint,g.wh-SUM(t2.WorkHours)
 FROM tbl t1 JOIN tbl t2 ON t1.Team = t2.Team AND t2.Sprint <= t1.Sprint
 JOIN 
   (SELECT SUM(WorkHours) AS wh, Team  FROM tbl GROUP BY Team) g ON t1.Team=g.Team
 GROUP BY t1.Team, t1.Sprint,g.wh

但随着行数的增加,三角形连接所需的工作量呈指数级增长。

答案 1 :(得分:1)

Select Team,
       isNull([1006], 0)+isNull([1007], 0)+isNull([1008], 0)+isNull([1009], 0)+isNull([1010], 0) as SP1005,
       isNull([1007], 0)+isNull([1008], 0)+isNull([1009], 0)+isNull([1010], 0) as SP1006,
       isNull([1008], 0)+isNull([1009], 0)+isNull([1010], 0) as SP1007,
       isNull([1009], 0)+isNull([1010], 0) as SP1008,
       isNull([1010], 0) as SP1009,
       0 as SP1010
  From YourTable
 PIVOT (Sum(WorkHours) For Sprint in ([1005],[1006],[1007],[1008],[1009],[1010])) p

问题是如果你想要它是动态的。在这种情况下,您应该使用动态SQL查询。动态查询的构建取决于几个方面:

  • 你想要变数吗? 列是否
  • 您想通过:

    a)第一个月/上个月或

    b)月份列表(例如逗号分隔)

    c)刚开始月份,查询应该返回当前月份的列

    d)刚开始月份,查询应该返回列表中的最后一个月

<强>已更新

SQL SERVER 2000的版本

Select Team,
       sum(SP1005) as SP1005,
       sum(SP1006) as SP1006,
       sum(SP1007) as SP1007,
       sum(SP1008) as SP1008,
       sum(SP1009) as SP1009,
       0 as SP1010
From (       
Select Team, 
       Case when Sprint in (1006, 1007, 1008, 1009, 1010) Then WorkHours  Else 0 end as SP1005,
       Case when Sprint in (1007, 1008, 1009, 1010) Then WorkHours  Else 0 end as SP1006,
       Case when Sprint in (1008, 1009, 1010) Then WorkHours  Else 0 end as SP1007,
       Case when Sprint in (1009, 1010) Then WorkHours  Else 0 end as SP1008,
       Case when Sprint in (1010) Then WorkHours  Else 0 end as SP1009
  From @t
) a  
 Group by Team

更新2:添加动态存储过程 (对于SQL Server 2000 +)

我假设您的Sprint列是整数。

Alter Procedure zzzGetTeamMonths( @FirstMonth int )
AS BEGIN
Declare @FirstMonthDate datetime
Declare @ActFirstMonth int
Declare @LastMonth int
Declare @LastMonthChar nvarchar(4)
Declare @nMonths int

Select @LastMonth=max(Sprint),
       @ActFirstMonth=min(Sprint)
  from zzzTest 
 Where Sprint >= @FirstMonth 

If @LastMonth >= @FirstMonth Begin
   -- Next line remove repeating columns from left side (for non-existant data)
   -- You can comment it out if you want to see all columns
   IF @ActFirstMonth>@FirstMonth Set @FirstMonth=@ActFirstMonth
   Set @nMonths = (@LastMonth/100-@FirstMonth/100)*12 + (@LastMonth-(@LastMonth/100)*100-@FirstMonth+(@FirstMonth/100)*100)
   Set @FirstMonthDate = convert(datetime, Right('0'+cast(@FirstMonth as varchar(4)),4)+'01',12) 
   Set @LastMonthChar = Right('0'+cast(@LastMonth as varchar(4)),4)

   Create Table #Months (id int, mnt nvarchar(4), mntp nvarchar(4)) 

   Insert Into #Months
   Select Number,
          Convert(nvarchar(4),Dateadd(month,number,@FirstMonthDate),12),
          Convert(nvarchar(4),Dateadd(month,number-1,@FirstMonthDate),12)
     From master.dbo.spt_values 
    Where type='P' and number<=@nMonths

   Declare @cmd nvarchar(4000)
   Declare @tmp nvarchar(4000)
   Declare @col nvarchar(4000)

   Select @tmp = '',
          @col = ''

   Select @col = @col + '
,sum(SP' + mntp + ') as SP' + mntp,
          @tmp = @tmp + '
,Case when Sprint between ' + mnt + ' and ' + @LastMonthChar + ' Then WorkHours  Else 0 end as SP' + mntp
        from #Months


   Drop Table #Months

   Select @cmd = '
SELECT Team' + @col + '
,0 as SP' + @LastMonthChar + ' 
FROM 
(
Select Team' + @tmp + ' 
From zzzTest 
) a  
Group by Team'  
  Print @cmd
  Exec (@cmd)
End
RETURN 0
END
GO