SQL服务器停止或中断执行的一个SQL脚本
-
20-08-2019 - |
题
有没有一种方法,以立即停止执行的一个SQL脚本SQL服务器,就像一个"突破"或"退出"的命令?
我有一个剧本,一些验证和查找它开始之前做的插入的,我希望它停止,如果任何验证或查找失败。
解决方案
的 raiserror 方法
raiserror('Oh no a fatal error', 20, -1) with log
这将终止连接,从而停止脚本的其余部分运行。
注意,这两个严重级别的20或更高, WITH LOG
选择是必要的,它以这种方式工作。
这甚至适用于好的陈述,例如。
print 'hi'
go
raiserror('Oh no a fatal error', 20, -1) with log
go
print 'ho'
会给你的输出:
hi
Msg 2745, Level 16, State 2, Line 1
Process ID 51 has raised user error 50000, severity 20. SQL Server is terminating this process.
Msg 50000, Level 20, State 1, Line 1
Oh no a fatal error
Msg 0, Level 20, State 0, Line 0
A severe error occurred on the current command. The results, if any, should be discarded.
注意到'ho'不打印。
注意事项:
- 这只是工作,如果你登录作为管理员('系统管理员的角色),而且还让你没有数据库连接。
- 如果你是不是记录在作为管理员,RAISEERROR()称自己会失败 和剧本将继续执行.
- 当调用sqlcmd.exe退出的代码2745会的报告。
该noexec方法
另一种方法,工作与去发言 set noexec on
.这会导致其他的脚本来会被跳过去了。它并不终止连接,但你需要打开 noexec
再次关闭之前的任何命令将执行。
例如:
print 'hi'
go
print 'Fatal error, script will not continue!'
set noexec on
print 'ho'
go
-- last line of the script
set noexec off -- Turn execution back on; only needed in SSMS, so as to be able
-- to run this script again in the same session.
其他提示
只需使用一个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模式没有打开,你会得到解析错误有关结肠。 Unfortuantely,仿佛运行脚本这不是一个完全防弹没有SQLCMD模式中,SQL枭雄工作室微风右过去甚至解析时错误!不过,如果你在命令行中运行它们,这是好的。
我不会用RAISERROR- SQL具有IF语句,可用于该目的。做你的验证和查询,并设置局部变量,然后用变量的值的IF语句,使插入条件。
您不会需要检查每一个验证测试的变量的结果。通常你能做到这一点,只有一个标志变量以确认所有条件传递:
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
即使你的验证是比较复杂的,你应该只需要几个标志变量在最终检查(S),包括
我成功地扩展开/关溶液使用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
在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。
这是一个存储过程?如果是这样,我认为你可以只是做一个回报,比如“返回NULL”;
此外refinig Sglasses方法中,上述线强制使用SQLCMD模式的,并且或者treminates的scirpt如果不使用SQLCMD模式或使用:on error exit
退出上的任何错误,点击
CONTEXT_INFO 是用于跟踪的状态。
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-------------
我建议你换你适当的代码块在try catch块。您可以依次用11严重性然后使用RAISERROR事件,如果你想打破到catch块。如果你只是想raiserrors而是继续在try块内执行,然后使用较低的严重性。
请感?
干杯, 约翰
[编辑,包括BOL参考
可以使用 GOTO语句改变执行的流程:
IF @ValidationResult = 0
BEGIN
PRINT 'Validation fault.'
GOTO EndScript
END
/* our code */
EndScript:
可以使用 RAISERROR 。
这些作品以“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 ...
。)
这是我的解决方案:
...
BEGIN
raiserror('Invalid database', 15, 10)
rollback transaction
return
END
您可以使用GOTO语句。尝试这个。这是使用全给你。
WHILE(@N <= @Count)
BEGIN
GOTO FinalStateMent;
END
FinalStatement:
Select @CoumnName from TableName
我用RETURN
这里所有的时间,工作在脚本或Stored Procedure
请确保您ROLLBACK
交易,如果你是在一个,否则立即RETURN
会造成一个开放的未提交的事务。
THX的回答!
raiserror()
工作正常,但你不应该忘记return
声明,否则脚本将继续没有错误! (hense的RAISERROR不是“throwerror” ;-))和如果必要的话,当然执行回滚!
raiserror()
是好的,告诉谁执行出现了错误的脚本的人。
如果你只是执行Management Studio中的脚本,并希望在第一个错误停止执行或回滚事务(如果使用),那么我认为最好的方法是使用try catch块(SQL 2005年以后)。 这种运作良好,在Management Studio中,如果您正在执行一个脚本文件。 存储过程总是可以使用这一点。
早在一天,我们采用了以下...最好的工作:
RAISERROR ('Error! Connection dead', 20, 127) WITH LOG