Sql-Server
在缺少 FETCH NEXT 的情況下防止無限循環
發現這個程式碼錯誤導致了生產中的死循環:
DECLARE @BatchID INT DECLARE MyCursor CURSOR FOR SELECT BatchID = ... OPEN MyCursor FETCH NEXT FROM MyCursor INTO @BatchID WHILE @@FETCH_STATUS = 0 BEGIN ... IF [condition] BEGIN ... FETCH NEXT FROM MyCursor INTO @BatchID END END CLOSE MyCursor DEALLOCATE MyCursor
假設需要一個游標是有保證的,有沒有辦法防止這個錯誤(除了更多的測試/程式碼審查)?
在其他語言中,我們
FOREACH
有為我們管理迭代進度的循環,或者FOR
是事後考慮的循環,那麼 SQL Server 中是否有任何等價物可以防止諸如放錯位置(或忘記!)之類的草率錯誤?我從未見過 SQL 中的自定義循環需要對游標做任何花哨
WHILE
的事情,並且循環具有相同的風險(以及@BatchID 為DELETE #WorkData WHERE ID = @BatchID
時的情況),那麼對於典型案例,如何以程式方式/乾淨地減輕這種風險?NULL
像這樣的方法非常不吸引人:
DECLARE @BatchID INT DECLARE MyCursor CURSOR FOR SELECT BatchID = -1--dummy entry to always be skipped UNION ALL SELECT BatchID = ... OPEN MyCursor FETCH NEXT FROM MyCursor INTO @BatchID WHILE @@FETCH_STATUS = 0 BEGIN FETCH NEXT FROM MyCursor INTO @BatchID IF @@FETCH_STATUS = 0 BEGIN ... END END CLOSE MyCursor DEALLOCATE MyCursor
在我看來,
@@FETCH_STATUS
在中間沒有任何游標位置/控制語句的情況下連續檢查兩次可能是 SQL Server猜測是否存在此類錯誤的有效方法,因為我使用游標的經驗從未見過連續兩次檢查故意(至少沒有嵌套游標,但那些仍然有控制語句,例如OPEN
和CLOSE
檢查@@FETCH_STATUS
外部游標之間)。PS
[condition]
這一次相當於“不是DST過渡日”(這是這個星期天)。更多時區錯誤!我對語言功能最感興趣,以實現與其他語言如何處理 for 循環的事後考慮子句(例如
i++
infor (int i = 0; i < myArray.Length; i++)
)相同的自動提供的保證。個人負責的事情越少,出錯的地方就越少,審計我們系統中成千上萬的儲存過程將是一項艱鉅的任務,特別是因為其中許多不恰當地迭代數據而不是使用已經基於集合的邏輯。
為了避免這樣的問題,我使用不同的模式進行獲取:
OPEN Cursor; WHILE 1=1 BEGIN FETCH NEXT FROM Cursor INTO [...]; IF @@FETCH_STATUS <> 0 BREAK; [...] END; CLOSE Cursor; DEALLOCATE Cursor;
在這種模式中,您
FETCH
只有一次,您也需要檢查一次獲取狀態。