このコードの誤りにより、PRODで無限ループが発生することがわかりました。
_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
ループ、または afterthought を持つFOR
ループがあるため、SQL Serverには、置き忘れ(または忘れるなど)などのずさんな間違いを防ぐ同等のループがあります。それ?
SQLのカスタムループがカーソルで何かを実行する必要があることを見たことがありません fancy と、WHILE
ループには同じリスクがあります(_DELETE #WorkData WHERE ID = @BatchID
_の場合も @ 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
_を続けて2回チェックすることは、SQL Serverが推測そのような間違いがあった場合、カーソルの私の経験では意図的に(少なくともネストされたカーソルなしで)行の2つのチェックを見たことがありませんが、それらには_@@FETCH_STATUS
_ ofのチェックの間にOPEN
とCLOSE
のような制御ステートメントがまだあります外側のカーソル)。
追伸今回の_[condition]
_は、「DST移行日ではない」(これはこの日曜日でした)と同等でした。その他のタイムゾーンのバグ!
このような問題を回避するために、フェッチに別のパターンを使用しています。
OPEN Cursor;
WHILE 1=1
BEGIN
FETCH NEXT FROM Cursor INTO [...];
IF @@FETCH_STATUS <> 0 BREAK;
[...]
END;
CLOSE Cursor;
DEALLOCATE Cursor;
このパターンでは、FETCHを1回だけ実行してから、フェッチ状況も1回確認する必要があります。