SQL Server – 停止或中断SQL脚本的执行

有没有办法立即停止SQL服务器中的SQL脚本执行,如“rest”或“退出”命令?

我有一个脚本,它开始做插入之前做一些validation和查找,我希望它停止,如果任何validation或查找失败。

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”angular色)身份login的情况,并且也没有数据库连接。
  • 如果您未以pipe理员身份login,则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 。 这会导致脚本的其余部分被跳过。 它不会终止连接,但是在任何命令执行之前,您都需要closuresnoexec

例:

 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模式没有打开,你会得到关于冒号的parsing错误。 不幸的是,如果脚本运行时没有处于SQLCMD模式,那么SQL Managment Studio甚至可以parsing错误! 不过,如果你从命令行运行它们,这没问题。

我不会使用RAISERROR SQL具有可用于此目的的IF语句。 执行validation和查找并设置局部variables,然后使用IF语句中variables的值使插入有条件。

您不需要检查每个validationtesting的variables结果。 通常你可以用一个标志variables来确认所有通过的条件:

 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 

即使您的validation更为复杂,您只需要在最终检查中包含一些标志variables即可。

你可以把你的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:

引发exception并将执行转移到TRY … CATCH构造的CATCH块…如果TRY … CATCH构造不可用,则会话结束。 设置发生exception的行号和过程。 严重性设置为16。

我使用事务成功地扩展了noexec开关解决scheme,以全部或全部方式运行脚本。

 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中的@finishedvariables,即使有错误并且执行被禁用。 但是,仅当执行未被禁用时,该值才被设置为1。 因此,我可以很好地提交或回滚相应的交易。

这是一个存储过程吗? 如果是这样,我认为你可以做一个返回,如“返回NULL”;

进一步的重新定义Sglasses方法,上面的代码强制使用SQLCMD模式,并且如果不使用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------------- 

我build议你把你的合适的代码块放在try catch块中。 然后,您可以使用严重性为11的Raiserror事件,以便在您希望的情况下打破catch块。 如果你只是想升级,但在try块内继续执行,那么使用较低的严重性。

合理?

干杯,约翰

[编辑包括BOL参考]

http://msdn.microsoft.com/en-us/library/ms175976(SQL.90).aspx

你可以使用RAISERROR 。

这是我的解决scheme:

 BEGIN raiserror('Invalid database', 15, 10) rollback transaction return END 

您可以使用GOTO语句改变执行stream程:

 IF @ValidationResult = 0 BEGIN PRINT 'Validation fault.' GOTO EndScript END /* our code */ EndScript: 

这些都没有用“GO”语句。 在这段代码中,无论严重性是10还是11,都会得到最终的PRINT语句。

testing脚本:

 -- ================================= 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 ...

你可以使用GOTO语句。 尝试这个。 这对你来说是完全的。

 WHILE(@N <= @Count) BEGIN GOTO FinalStateMent; END FinalStatement: Select @CoumnName from TableName 

我一直使用RETURN,在脚本或SP中工作

如果你在一个,确保你ROLLBACK交易,否则立即返回将导致一个开放的未提交的交易

Thx的答案!

raiserror()工作正常,但你不应该忘记return语句,否则脚本继续没有错误! (hesese raiserror不是一个“throwerror”;-)),当然如果有必要回滚!

raiserror()很高兴告诉执行脚本的人出了什么问题。

如果您只是在Management Studio中执行一个脚本,并希望在第一个错误时停止执行或回滚事务(如果使用的话),那么我认为最好的方法是使用try catch块(SQL 2005以后)。 如果您正在执行脚本文件,这在pipe理工作室中运行良好。 存储过程总是可以使用这个。