2013-08-05 108 views
0

我正在爲我們運行的網站編寫一個成就模塊。這段代碼將在給定的時間範圍結束時在SQL Server上運行,以獎勵成果(下次訪問該網站時將通過客戶端通知)。如何替換嵌套遊標?

所以我需要看看所有的團隊和所有的「最終」成就(這是獨立的團隊)。每項成就都有一個或多個必須符合的規則。一旦我確定成績通過了,我就會將該成就獎給該團隊的所有參與者。

我是通過遊標處理這一點,我得到了一個錯誤,所以當我去谷歌問題,我上的論壇上無休止的鏈接「你傻乎乎$ &#$爲什麼你使用遊標」(意譯) 。我想,當我解決我的問題的時候,我可能會更換我使用的基於集合的方法(如果可能的話)。

我發現的另一個例子是所有基本的更新場景,在表格上使用單個嵌套循環來實現相互之間的密鑰交互,老實說,我不會考慮在這些場景中使用遊標來開始。

我下面的內容是而不是完全在句法上是正確的,但我可以通過玩弄自己來解決這個問題。這應該給的什麼,我試圖完成一個清晰的思路,但是:

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; 

是否有一個基於集合的替代我在這裏做什麼?我需要補充的是,這是針對一小部分記錄運行的,所以表現並不是我關心的問題;未來龐大更新的最佳實踐。

回答

1

爲了使這個基於集合,你需要修復你正在調用的過程,以便他們有一個表值參數或proc中的代碼加入到你有你想要處理的記錄的表中。在第二種情況下,您可以將它們標記爲已處理或在完成時刪除它們。

+0

感謝您的幫助!當然,這是一種更有效和正確的做事方式。 – Ryan