web-dev-qa-db-ja.com

SQL Server-カーソル-不足している後付け-FETCH NEXTが不足している場合の無限ループに対する保護

このコードの誤りにより、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のチェックの間にOPENCLOSEのような制御ステートメントがまだあります外側のカーソル)。

追伸今回の_[condition]_は、「DST移行日ではない」(これはこの日曜日でした)と同等でした。その他のタイムゾーンのバグ!

1
Elaskanator

このような問題を回避するために、フェッチに別のパターンを使用しています。

OPEN Cursor;

WHILE 1=1
BEGIN 

    FETCH NEXT FROM Cursor INTO [...];
    IF @@FETCH_STATUS <> 0 BREAK;

    [...]

END;

CLOSE Cursor;
DEALLOCATE Cursor;

このパターンでは、FETCHを1回だけ実行してから、フェッチ状況も1回確認する必要があります。

4
Piotr