我在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上执行此操作。这对我来说真的很难。有人可以帮忙吗?非常感谢!
编辑或者你可以忽略行到列的转换部分(我知道该怎么做),只关注积累部分。
答案 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