有没有办法立即停止在SQL Server中执行SQL脚本,如"break"或"exit"命令?
我有一个脚本在开始插入之前执行一些验证和查找,我希望它在任何验证或查找失败时停止.
该RAISERROR方法
raiserror('Oh no a fatal error', 20, -1) with log
这将终止连接,从而停止脚本的其余部分运行.
请注意,严重级别为20或更高级别以及WITH LOG
选项对于它以这种方式工作是必要的.
这甚至适用于GO语句,例如.
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'未打印.
注意事项:
这仅在您以admin('sysadmin'角色)登录时才有效,并且还使您没有数据库连接.
如果您未以管理员身份登录,则RAISEERROR()调用本身将失败,脚本将继续执行.
使用sqlcmd.exe调用时,将报告退出代码2745.
参考:http://www.mydatabasesupport.com/forums/ms-sqlserver/174037-sql-server-2000-abort-whole-script.html#post761334
noexec方法
使用GO语句的另一种方法是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模式,您将获得有关冒号的解析错误.不幸的是,它并不是完全没有防御性的,就好像脚本是在没有处于SQLCMD模式的情况下运行一样,SQL Managment Studio正好经过了解析时间错误!不过,如果你从命令行运行它们,这很好.
我不会使用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
即使您的验证更复杂,您也只需要在最终检查中包含一些标志变量.
我成功地使用事务扩展了noexec开/关解决方案,以全有或全无的方式运行脚本.
set noexec off begin transaction gogo if @@error != 0 set noexec on; 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 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.
您可以将您的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
这是一个存储过程吗?如果是这样,我认为你可以做一个Return,比如"Return NULL";
进一步的refinig Sglasses方法,上面的行强制使用SQLCMD模式,如果不使用SQLCMD模式则使用scirpt或者使用: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-------------
您可以使用GOTO语句更改执行流程:
IF @ValidationResult = 0 BEGIN PRINT 'Validation fault.' GOTO EndScript END /* our code */ EndScript:
我建议你在try catch块中包装适当的代码块.然后,您可以使用严重性为11的Raiserror事件,以便在需要时中断到catch块.如果您只是希望使用raiserrors但在try块中继续执行,则使用较低的严重性.
合理?
干杯,约翰
[编辑包括BOL参考]
http://msdn.microsoft.com/en-us/library/ms175976(SQL.90).aspx