我正在为我们运行的网站编写成就模块。这段特定的代码将在给定时间范围结束时在 SQL Server 上运行以奖励成就(下次访问该站点时将通过客户端通知)。
所以我需要查看所有团队和所有“最终”成就(独立于团队)。每个成就都有一个或多个必须满足的规则。一旦我确定该成就通过了,我就会将该成就奖励给该团队的所有参与者。
我是通过游标来处理这个问题的,我遇到了一个错误,所以当我去谷歌搜索这个问题时,我在“你 DUMB $&#$ 为什么你使用游标”的论坛上得到了无穷无尽的链接(解释一下)。我想在解决问题的同时,我也可以使用基于集合的方法(如果可能的话)替换我所拥有的东西。
我发现的替代示例都是在具有键的表上使用单个嵌套循环的所有基本更新场景,而且老实说,我不会考虑在这些场景中开始使用游标。
我在下面的内容在语法上并不完全正确,但我可以通过玩弄自己来解决这个问题。但是,这应该可以清楚地了解我要完成的工作:
declare @TimeframeID int;
declare @AchievementID int;
declare @q1 int;
declare @q2 int;
declare @TeamID int;
declare @TotalReg int;
declare @TotalMin int;
declare @AvgMin decimal(10, 2);
declare @AggType varchar(50);
declare @Pass bit = 1;
declare @Email varchar(50);
declare @ParticipantID int;
select @TimeframeID = MAX(TimeframeID) from Timeframes
where IsActive = 1;
declare team_cur CURSOR FOR
select
t.TeamID,
(select COUNT(1) from Registrations r
where r.TeamID = t.TeamID and r.TimeframeID = @TimeframeID) TotalReg,
(select SUM(Minutes) from Activities a
inner join Registrations r on r.RegistrationID = a.RegistrationID
where r.TeamID = t.TeamID and r.TimeframeID = @TimeframeID) TotalMin
from Teams t
where Active = 1
group by TeamID;
declare ach_cur CURSOR FOR
select AchievementID from luAchievements
where TimeframeID = @TimeframeID and AchievementType = 'End';
declare rule_cur CURSOR for
select Quantity1, Quantity2, AggregateType
from AchievementRule_Links arl
inner join luAchievementRules ar on ar.RuleID = arl.RuleID
where arl.AchievementID = @AchievementID;
open team_cur;
fetch next from team_cur
into @TeamID, @TotalReg, @TotalMin;
while @@FETCH_STATUS = 0
begin
open ach_cur;
fetch next from ach_cur
into @AchievementID;
while @@FETCH_STATUS = 0
begin
open rule_cur;
fetch next from rule_cur
into @q1, @q2, @AggType;
while @@FETCH_STATUS = 0
begin
if @AggType = 'Total'
begin
if @q1 > @TotalReg
begin
set @Pass = 0;
end
end
else if @AggType = 'Average'
begin
print 'do this later; need to get specs';
end
fetch next from rule_cur
into @q1, @q2, @AggType;
end
close rule_cur;
deallocate rule_cur;
-- if passed, award achievement to all team members
if @Pass = 1
begin
declare reg_cursor cursor for
select max(p.Email) from Participants p
inner join Registrations reg on reg.ParticipantID = p.ParticipantID
where reg.TeamID = @TeamID;
open reg_cursor;
fetch next from reg_cursor
into @Email;
while @@FETCH_STATUS = 0
begin
exec ProcessAchievement @AchievementID, @Email, 0;
fetch next from reg_cursor
into @Email;
end
close reg_cursor;
deallocate reg_cursor;
-- award achievement to team
exec ProcessTeamAchievement @AchievementID, @TeamID;
end
fetch next from ach_cur
into @AchievementID;
end
close ach_cur;
deallocate ach_cur;
fetch next from team_cur
into @TeamID, @TotalReg, @TotalMin;
end
close team_cur;
deallocate team_cur;
我在这里做的事情是否有基于集合的替代方案?我需要补充一点,这是针对一小组记录运行的,所以性能不是我关心的;未来庞大更新的最佳实践是。