私はSQLスクリプトに取り組んでおり、いくつかの条件が満たされない場合はスクリプトの続行を停止する必要があります。
GoogleでGoogleを実行すると、重大度レベルが20のRaisErrorで終了することがわかりました。しかし、いくつかの理由でそのオプションを使用できません。
SQLスクリプトの実行を停止するための可能な代替手段を教えてください。
RAISERRORドキュメント (強調は私のもの)から:
0から18までの重大度レベルは、すべてのユーザーが指定できます。 重大度レベル19〜25は、sysadmin固定サーバーロールのメンバーまたはALTER TRACE権限を持つユーザーのみが指定できます。重大度レベル19〜25の場合、WITH LOGオプションが必要です。
これらの基準を満たしていないため、スクリプトを実行しているプリンシパルである可能性が高いです。
RAISERROR
の使用には何の問題もありません。過度の重大度レベルを使用しているだけです。発生したエラーのデフォルトとしてレベル16を使用すると、シーケンスが終了します。より正確にしたい場合は、Microsoft自体によって指定されたレベルに従うことができます。
さて、スクリプトのコンテキストによっては、RAISERROR
を使用しても、それ自体では(通常の重大度レベルを使用して)スクリプトを「終了」しないため、十分ではない場合があります。
例えば:
RAISERROR(N'Test', 16, 1);
SELECT 1; /* Executed! */
これは両方エラーを発生し、結果セットを返します。
スクリプトをすぐに終了するには、 RETURN
を使用することをお勧めします(GOTO
- type構成の使用は、代替手段が存在するほとんどのプログラミングサークルでは一般的に推奨されていません)。
RAISERROR(N'Test', 16, 1);
RETURN;
SELECT 1; /* Not executed */
または TRY/CATCH
を使用してエラーを処理します。重大度が11以上の場合、実行はCATCH
ブロックにジャンプします。
BEGIN TRY
RAISERROR(N'Test', 16, 1);
SELECT 1; /* Not executed */
END TRY
BEGIN CATCH
SELECT 2; /* Executed */
END CATCH
BEGIN TRY
RAISERROR(N'Test', 10, 1);
SELECT 1; /* Executed */
END TRY
BEGIN CATCH
SELECT 2; /* Not executed */
END CATCH
別の問題は、スクリプトが複数のバッチにまたがっている場合です-RETURN
はbatchを終了するだけです:
RAISERROR(N'Test', 16, 1);
RETURN;
SELECT 1; /* Not executed */
GO
SELECT 2; /* Executed! */
これを修正するには、各バッチの開始時に @@ERROR
を確認します。
RAISERROR(N'Test', 16, 1);
RETURN;
SELECT 1; /* Not executed */
GO
IF (@@ERROR != 0)
RETURN;
SELECT 2; /* Not executed */
編集:Martin Smithがコメントで正しく指摘しているので、これは2つのバッチに対してのみ機能します。 3つ以上のバッチに拡張するには、次のようにカスケードエラーを発生させることができます(注:GOTO
メソッドは、バッチ内でターゲットラベルを定義する必要があるため、この問題を解決しません)。
RAISERROR(N'Test', 16, 1);
RETURN;
SELECT 1; /* Not executed */
GO
IF (@@ERROR != 0)
BEGIN
RAISERROR(N'Error already raised. See previous errors.', 16, 1);
RETURN;
END
SELECT 2; /* Not executed */
GO
IF (@@ERROR != 0)
BEGIN
RAISERROR(N'Error already raised. See previous errors.', 16, 1);
RETURN;
END
SELECT 3; /* Not executed */
または、彼も指摘しているように、環境に適している場合は SQLCMD
method を使用できます。
GOTO
ステートメントを使用して、好きな場所をスキップできます。つまり、エラーやその他の条件が発生し、スクリプトの下部にラベルを付けることができます(つまり、TheEndOfTheScript:
)を発行し、goto TheEndOfTheScript;
ステートメント。
ここに簡単なサンプルがあります:
print 'here is the first statement...';
print 'here is the second statement...';
-- substitute whatever conditional flow determining factor
-- you'd like here. I have chosen a dummy statement that will
-- always return true
--
if (1 = 1)
goto TheEndOfTheScript;
print 'here is the third statement...';
print 'here is the fourth statement...';
TheEndOfTheScript:
print 'here is the end of the script...';
この実行の出力は次のようになります。
here is the first statement...
here is the second statement...
here is the end of the script...
ご覧のとおり、GOTO
は3番目と4番目のステートメントの印刷をスキップし、ラベル(TheEndOfTheScript
)にジャンプしました。
最良の方法は、SET NOEXEC ONを使用することです
詳細については、こちらをご覧ください。 SQL SERVERの条件に基づいて、現在のバッチとGOステートメントで区切られた後続のバッチでステートメントの実行を停止または中止または中断する方法
SET NOEXEC ON/OFF
に同意しますが、ストアドプロシージャ(単一のブロックを含む)ではRETURN
ステートメントを使用します。
警告:スクリプトファイルで、複数のGO
ステートメントがある場合、RETURN
は現在のブロックからのみ取得され、次のブロック/バッチを続行します。
注:GOTO
は不適切なコーディング手法であると考えられています。 "TRY..CATCH
"の使用をお勧めします。これはSQL Server 2008以降に導入され、2012年にTHROW
が続いたためです。