如何在存储过程中退出?
我有一个存储过程,我想尽早退出(同时尝试调试它)。我尝试拨打
RETURN
和 RAISERROR
,sp 继续运行:
CREATE PROCEDURE dbo.Archive_Session @SessionGUID uniqueidentifier AS
print 'before raiserror'
raiserror('this is a raised error', 18, 1)
print 'before return'
return -1
print 'after return'
[snip]
我知道它会继续运行,因为我在下面遇到了错误。我没有看到任何我的指纹。如果我注释掉大部分存储过程:
CREATE PROCEDURE dbo.Archive_Session @SessionGUID uniqueidentifier AS
print 'before raiserror'
raiserror('this is a raised error', 18, 1)
print 'before return'
return -1
print 'after return'
/*
[snip]
*/
然后我就没有收到错误,并且看到了结果:
before raiserror
Server: Msg 50000, Level 18, State 1, Procedure Archive_Session, Line 5
this is a raised error
before return
所以问题是:如何摆脱 SQL Server 中的存储过程?
您可以使用
RETURN
立即停止存储过程的执行。引用自在线图书:
无条件退出查询或 程序。立即退货 完整且可以随时使用 退出过程、批处理或 语句块。声明称 follow RETURN 不被执行。
出于偏执,我尝试了你的示例,它确实输出了 PRINT 并立即停止执行。
除非您指定严重性为 20 或更高,否则
raiserror
将不会停止执行。 请参阅 MSDN 文档。
正常的解决方法是在每个
return
之后添加 raiserror
:
if @whoops = 1
begin
raiserror('Whoops!', 18, 1)
return -1
end
将其放入
TRY/CATCH
。
当 RAISERROR 以严重程度运行时 TRY 块中的 11 或更高,它 将控制权转移给关联的 捕获块
参考:MSDN。
编辑: 这适用于 MSSQL 2005+,但我看到您现在已经澄清您正在使用 MSSQL 2000。我将把它留在这里供参考。
我明白了为什么
RETURN
没有无条件地从存储过程返回。我看到的错误是在存储过程被编译时,而不是在执行时。
考虑一个假想的存储过程:
CREATE PROCEDURE dbo.foo AS
INSERT INTO ExistingTable
EXECUTE LinkedServer.Database.dbo.SomeProcedure
即使这个存储过程包含错误(也许是因为对象的列数不同,也许表中有时间戳列,也许存储过程不存在),您仍然可以
保存它。您可以保存它,因为您正在引用链接服务器。
但是当您实际执行
存储过程时,SQL Server 然后编译它,并生成查询计划。 我的错误不是在第 114 行发生,而是在第 114 行发生。SQL Server 无法编译存储过程,这就是它失败的原因。
这就是为什么RETURN
没有返回,因为它甚至还没有开始。
这在这里有效。
ALTER PROCEDURE dbo.Archive_Session
@SessionGUID int
AS
BEGIN
SET NOCOUNT ON
PRINT 'before raiserror'
RAISERROR('this is a raised error', 18, 1)
IF @@Error != 0
RETURN
PRINT 'before return'
RETURN -1
PRINT 'after return'
END
go
EXECUTE dbo.Archive_Session @SessionGUID = 1
before raiserror
Msg 50000, Level 18, State 1, Procedure Archive_Session, Line 7
this is a raised error
这似乎有很多代码,但这是我发现的最好的方法。
ALTER PROCEDURE Procedure
AS
BEGIN TRY
EXEC AnotherProcedure
END TRY
BEGIN CATCH
DECLARE @ErrorMessage NVARCHAR(4000);
DECLARE @ErrorSeverity INT;
DECLARE @ErrorState INT;
SELECT
@ErrorMessage = ERROR_MESSAGE(),
@ErrorSeverity = ERROR_SEVERITY(),
@ErrorState = ERROR_STATE();
RAISERROR (@ErrorMessage, -- Message text.
@ErrorSeverity, -- Severity.
@ErrorState -- State.
);
RETURN --this forces it out
END CATCH
--Stuff here that you do not want to execute if the above failed.
END --end procedure
这是因为你没有
BEGIN
和
END
Statement Completed
(或类似的东西)。