「break」コマンドや「exit」コマンドのように、SQL サーバーで SQL スクリプトの実行をすぐに停止する方法はありますか?
挿入を開始する前にいくつかの検証とルックアップを行うスクリプトがあり、検証またはルックアップのいずれかが失敗した場合はスクリプトを停止したいと考えています。
「break」コマンドや「exit」コマンドのように、SQL サーバーで SQL スクリプトの実行をすぐに停止する方法はありますか?
挿入を開始する前にいくつかの検証とルックアップを行うスクリプトがあり、検証またはルックアップのいずれかが失敗した場合はスクリプトを停止したいと考えています。
RETURN を使用するだけです (ストアド プロシージャの内外で機能します)。
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 は解析時間のエラーさえも通り過ぎてしまうため、完全に防弾というわけではありません。それでも、コマンド ラインから実行している場合は問題ありません。
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
検証がより複雑な場合でも、最終チェックに含める必要があるのはいくつかのフラグ変数だけです。
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 に設定されています。
私は 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 に設定されます。したがって、それに応じてトランザクションをうまくコミットまたはロールバックできます。
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
GOTOステートメントを使用して実行の流れを変更できます。
IF @ValidationResult = 0
BEGIN
PRINT 'Validation fault.'
GOTO EndScript
END
/* our code */
EndScript:
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-------------
これはストアドプロシージャですか?もしそうなら、「Return NULL」などの Return を実行できると思います。
これらはどれも「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 ...
。)
RAISERRORを使用できます。
GOTO ステートメントを使用できます。これを試して。これはあなたのために完全に使用されています。
WHILE(@N <= @Count)
BEGIN
GOTO FinalStateMent;
END
FinalStatement:
Select @CoumnName from TableName
これが私の解決策でした:
...
BEGIN
raiserror('Invalid database', 15, 10)
rollback transaction
return
END
Management Studioでスクリプトを実行しているだけで、最初のエラーで実行またはロールバックトランザクション(使用されている場合)を停止したい場合は、try catchブロック(SQL 2005以降)を使用するのが最善の方法です。スクリプトファイルを実行している場合、これはManagementStudioでうまく機能します。ストアドプロシージャは常にこれを使用することもできます。
答えてくれてありがとう!
raiserror()
return
正常に動作しますが、ステートメントを忘れないでください。そうしないと、スクリプトはエラーなしで続行されます! (したがって、raiserror は「throwerror」ではありません ;-)) もちろん、必要に応じてロールバックを実行します!
raiserror()
スクリプトを実行する人に何か問題が発生したことを伝えるのは良いことです。