web-dev-qa-db-ja.com

SQLスクリプトの実行を中断する方法

私はSQLスクリプトに取り組んでおり、いくつかの条件が満たされない場合はスクリプトの続行を停止する必要があります。

GoogleでGoogleを実行すると、重大度レベルが20のRaisErrorで終了することがわかりました。しかし、いくつかの理由でそのオプションを使用できません。

SQLスクリプトの実行を停止するための可能な代替手段を教えてください。

16
New Developer

RAISERRORドキュメント (強調は私のもの)から:

0から18までの重大度レベルは、すべてのユーザーが指定できます。 重大度レベル19〜25は、sysadmin固定サーバーロールのメンバーまたはALTER TRACE権限を持つユーザーのみが指定できます。重大度レベル19〜25の場合、WITH LOGオプションが必要です。

これらの基準を満たしていないため、スクリプトを実行しているプリンシパルである可能性が高いです。

RAISERRORの使用には何の問題もありません。過度の重大度レベルを使用しているだけです。発生したエラーのデフォルトとしてレベル16を使用すると、シーケンスが終了します。より正確にしたい場合は、Microsoft自体によって指定されたレベルに従うことができます。

enter image description here

さて、スクリプトのコンテキストによっては、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

別の問題は、スクリプトが複数のバッチにまたがっている場合です-RETURNbatchを終了するだけです:

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 を使用できます。

8
Jon Seigel

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)にジャンプしました。

6
Thomas Stringer
4
Yogesh

SET NOEXEC ON/OFFに同意しますが、ストアドプロシージャ(単一のブロックを含む)ではRETURNステートメントを使用します。

警告:スクリプトファイルで、複数のGOステートメントがある場合、RETURNは現在のブロックからのみ取得され、次のブロック/バッチを続行します。

注:GOTOは不適切なコーディング手法であると考えられています。 "TRY..CATCH"の使用をお勧めします。これはSQL Server 2008以降に導入され、2012年にTHROWが続いたためです。

0
Eddie Kumar