2017-02-20 103 views
-1

我創建了一個存儲過程來處理那些表上的數據。我是否應該避免在SQL中使用循環?

爲了讓我處理這些數據,我必須做一個while循環,因爲我必須計算一個表上不存在的結束日期。

第一條記錄的結束日期應該是第二條記錄的開始日期-1天。

現在,當我向大四介紹這件事時,他告訴我,在存儲過程中使用循環是個很大的問題。我所提供的解決方案是使用該表創建一個視圖,並在其上創建多個聯合以生成我需要的缺失數據。

我的循環方法錯了嗎?我今後是否應該避免在我的存儲過程中使用循環?

+2

SQL是聲明;存儲過程是程序性的。我會盡我所能去看看在我使用存儲過程之前是否可以聲明性地滿足要求。沒有循環。 – duffymo

+2

循環往往不是一個不錯的選擇。嘗試沒有一個。循環中的「逐行」處理也稱爲「緩慢」 –

+0

而不是使用循環,可以使用窗口化表達式('over ... partition')或使用複雜連接。循環使用90%的情況在SQL中不是很好的做法。 – Fka

回答

1

在處理可能需要循環的問題時,使用基於集合的方法總是一個好主意。

幾乎總是你的while/for循環可以與條件連接交換來使其基於set。如果它是您需要的計數器,請嘗試使用計數表。一個循環的

實施例轉化使用JOIN設置的問題是像下面

SELECT DISTINCT A.StartDate, B.EndDate 
FROM 
A LEFT JOIN B 
ON DATEDIFF(d,A.EndDate,B.StartDate)=1 
1

它始終是更好爲包括代碼,與樣品數據一起說明你的情況,並與樣品結果描述您想要的結果爲給定的樣本數據設置。參見:How to post a tsql question on a public forumHow-to-Ask

它幾乎是總是比較好避免任何種類的whilecursor。在你描述的情況下,我相信你可以通過利用lead()窗口函數來避免while循環或多個union查詢。

實施例使用lead()common table expression:使用在派生表/聯視圖一個lead()

;with cte as (
    select t.* 
    , NextStartDate = lead(StartDate) over (
     partition by ForEachOfThisColumn -- e.g. AccountId, AssignmentId 
     order by StartDate asc 
    ) 
    from t 
) 
select cte.* 
    , EndDate = dateadd(day, -1, NextStartDate) 
from cte; 

實施例:

select cte.* 
    , EndDate = dateadd(day, -1, NextStartDate) 
from (
    select t.* 
    , NextStartDate = lead(StartDate) over (
     partition by ForEachOfThisColumn -- e.g. AccountId, AssignmentId 
     order by StartDate asc 
    ) 
    from t 
) as cte;