364

「break」コマンドや「exit」コマンドのように、SQL サーバーで SQL スクリプトの実行をすぐに停止する方法はありますか?

挿入を開始する前にいくつかの検証とルックアップを行うスクリプトがあり、検証またはルックアップのいずれかが失敗した場合はスクリプトを停止したいと考えています。

4

21 に答える 21

201

RETURN を使用するだけです (ストアド プロシージャの内外で機能します)。

于 2009-03-18T17:23:19.433 に答える
59

SQLCMD モードを使用できる場合は、呪文

:on error exit

(コロンを含む) は、RAISERROR が実際にスクリプトを停止する原因となります。例えば、

:on error exit

IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[SOMETABLE]') AND type in (N'U')) 
    RaisError ('This is not a Valid Instance Database', 15, 10)
GO

print 'Keep Working'

出力します:

Msg 50000, Level 15, State 10, Line 3
This is not a Valid Instance Database
** An error was encountered during execution of batch. Exiting.

バッチは停止します。SQLCMD モードがオンになっていない場合、コロンに関する解析エラーが発生します。残念ながら、SQLCMD モードにせずにスクリプトを実行した場合、SQL Managment Studio は解析時間のエラーさえも通り過ぎてしまうため、完全に防弾というわけではありません。それでも、コマンド ラインから実行している場合は問題ありません。

于 2010-04-07T06:13:39.770 に答える
21

RAISERROR は使用しません。SQL には、この目的で使用できる IF ステートメントがあります。検証とルックアップを実行し、ローカル変数を設定してから、IF ステートメントで変数の値を使用して挿入を条件付きにします。

すべての検証テストの可変結果をチェックする必要はありません。すべての条件が渡されたことを確認するには、通常、フラグ変数を 1 つだけ使用してこれを行うことができます。

declare @valid bit

set @valid = 1

if -- Condition(s)
begin
  print 'Condition(s) failed.'
  set @valid = 0
end

-- Additional validation with similar structure

-- Final check that validation passed
if @valid = 1
begin
  print 'Validation succeeded.'

  -- Do work
end

検証がより複雑な場合でも、最終チェックに含める必要があるのはいくつかのフラグ変数だけです。

于 2009-03-18T17:07:12.763 に答える
17

SQL 2012+ では、 THROWを使用できます。

THROW 51000, 'Stopping execution because validation failed.', 0;
PRINT 'Still Executing'; -- This doesn't execute with THROW

MSDN から:

例外を発生させ、実行を TRY…CATCH コンストラクトの CATCH ブロックに転送します。TRY…CATCH コンストラクトが使用できない場合、セッションは終了します。例外が発生する行番号と手順を設定します。重大度は 16 に設定されています。

于 2015-11-19T16:21:15.520 に答える
14

私は noexec オン/オフ ソリューションをトランザクションで拡張し、スクリプトをオール オア ナッシング方式で実行しました。

set noexec off

begin transaction
go

<First batch, do something here>
go
if @@error != 0 set noexec on;

<Second batch, do something here>
go
if @@error != 0 set noexec on;

<... etc>

declare @finished bit;
set @finished = 1;

SET noexec off;

IF @finished = 1
BEGIN
    PRINT 'Committing changes'
    COMMIT TRANSACTION
END
ELSE
BEGIN
    PRINT 'Errors occured. Rolling back changes'
    ROLLBACK TRANSACTION
END

エラーが発生して実行が無効になった場合でも、コンパイラは IF の @finished 変数を「理解」しているようです。ただし、実行が無効にされていない場合にのみ、値は 1 に設定されます。したがって、それに応じてトランザクションをうまくコミットまたはロールバックできます。

于 2011-10-25T12:27:31.450 に答える
12

SQLステートメントをWHILEループでラップし、必要に応じてBREAKを使用できます

WHILE 1 = 1
BEGIN
   -- Do work here
   -- If you need to stop execution then use a BREAK


    BREAK; --Make sure to have this break at the end to prevent infinite loop
END
于 2009-03-18T17:27:14.947 に答える
12

GOTOステートメントを使用して実行の流れを変更できます。

IF @ValidationResult = 0
BEGIN
    PRINT 'Validation fault.'
    GOTO EndScript
END

/* our code */

EndScript:
于 2016-12-09T15:21:25.497 に答える
11

Sglasses メソッドをさらに改良すると、上記の行は SQLCMD モードの使用を強制し、SQLCMD モードを使用していない場合はスクリプトを終了するか、状態を追跡するために CONTEXT_INFO:on error exitを使用してエラーが発生した場合に終了します。

SET CONTEXT_INFO  0x1 --Just to make sure everything's ok
GO 
--treminate the script on any error. (Requires SQLCMD mode)
:on error exit 
--If not in SQLCMD mode the above line will generate an error, so the next line won't hit
SET CONTEXT_INFO 0x2
GO
--make sure to use SQLCMD mode ( :on error needs that)
IF CONTEXT_INFO()<>0x2 
BEGIN
    SELECT CONTEXT_INFO()
    SELECT 'This script must be run in SQLCMD mode! (To enable it go to (Management Studio) Query->SQLCMD mode)\nPlease abort the script!'
    RAISERROR('This script must be run in SQLCMD mode! (To enable it go to (Management Studio) Query->SQLCMD mode)\nPlease abort the script!',16,1) WITH NOWAIT 
    WAITFOR DELAY '02:00'; --wait for the user to read the message, and terminate the script manually
END
GO

----------------------------------------------------------------------------------
----THE ACTUAL SCRIPT BEGINS HERE-------------
于 2010-08-24T14:02:13.647 に答える
8

これはストアドプロシージャですか?もしそうなら、「Return NULL」などの Return を実行できると思います。

于 2009-03-18T17:07:52.870 に答える
5

これらはどれも「GO」ステートメントでは機能しません。このコードでは、重大度が 10 か 11 かに関係なく、最終的な PRINT ステートメントを取得します。

テスト スクリプト:

-- =================================
PRINT 'Start Test 1 - RAISERROR'

IF 1 = 1 BEGIN
    RAISERROR('Error 1, level 11', 11, 1)
    RETURN
END

IF 1 = 1 BEGIN
    RAISERROR('Error 2, level 11', 11, 1)
    RETURN
END
GO

PRINT 'Test 1 - After GO'
GO

-- =================================
PRINT 'Start Test 2 - Try/Catch'

BEGIN TRY
    SELECT (1 / 0) AS CauseError
END TRY
BEGIN CATCH
    SELECT ERROR_MESSAGE() AS ErrorMessage
    RAISERROR('Error in TRY, level 11', 11, 1)
    RETURN
END CATCH
GO

PRINT 'Test 2 - After GO'
GO

結果:

Start Test 1 - RAISERROR
Msg 50000, Level 11, State 1, Line 5
Error 1, level 11
Test 1 - After GO
Start Test 2 - Try/Catch
 CauseError
-----------

ErrorMessage
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Divide by zero error encountered.

Msg 50000, Level 11, State 1, Line 10
Error in TRY, level 11
Test 2 - After GO

これを機能させる唯一の方法は、スクリプトをGOステートメントなしで記述することです。時にはそれは簡単です。時々それはかなり難しいです。(のようなものを使用してくださいIF @error <> 0 BEGIN ...。)

于 2009-03-18T21:10:16.127 に答える
4

RAISERRORを使用できます。

于 2009-03-18T17:05:27.930 に答える
3

GOTO ステートメントを使用できます。これを試して。これはあなたのために完全に使用されています。

WHILE(@N <= @Count)
BEGIN
    GOTO FinalStateMent;
END

FinalStatement:
     Select @CoumnName from TableName
于 2015-09-07T06:58:18.527 に答える
3

これが私の解決策でした:

...

BEGIN
    raiserror('Invalid database', 15, 10)
    rollback transaction
    return
END
于 2012-06-27T08:40:44.163 に答える
1

Management Studioでスクリプトを実行しているだけで、最初のエラーで実行またはロールバックトランザクション(使用されている場合)を停止したい場合は、try catchブロック(SQL 2005以降)を使用するのが最善の方法です。スクリプトファイルを実行している場合、これはManagementStudioでうまく機能します。ストアドプロシージャは常にこれを使用することもできます。

于 2012-07-05T07:34:31.370 に答える
1

答えてくれてありがとう!

raiserror()return正常に動作しますが、ステートメントを忘れないでください。そうしないと、スクリプトはエラーなしで続行されます! (したがって、raiserror は「throwerror」ではありません ;-)) もちろん、必要に応じてロールバックを実行します!

raiserror()スクリプトを実行する人に何か問題が発生したことを伝えるのは良いことです。

于 2009-03-31T13:52:18.187 に答える