尝试和抓住TSQL - 赶不捕获
我有一个存储过程,似乎没有正确记录其错误。尝试和抓住TSQL - 赶不捕获
代码错误,但catch块似乎不会生效。
try块相当长 - 但错误部分很简单,并在最后直接出现,所以我已经精确定义了这一点。
BEGIN TRY
insert into tbl_X
select * from #temp_tbl_Y
RETURN 1
END TRY
BEGIN CATCH
Insert Into ExtractsErrorLog
SELECT
getdate() as ErrorDate
,object_name(@@procid) as ProcedureName
,ERROR_NUMBER() as ErrorNumber
,ERROR_LINE() as ErrorLine
,ERROR_MESSAGE() as ErrorMessage
;
DECLARE @errormessage as varchar(max);
DECLARE @errorseverity as int;
DECLARE @errorstate as int;
set @errormessage = ERROR_MESSAGE();
set @errorseverity = ERROR_SEVERITY();
set @errorstate = ERROR_STATE();
RAISERROR (@errormessage,
@errorseverity,
@errorstate
);
END CATCH;
的PROC失败上的错误是我们的老朋友 “列名或所提供值不匹配表定义的数量。” 我修复了这个错误 - 这是一个愚蠢的懒惰错误 - 但我很困惑为什么我的错误日志记录过程似乎没有工作 - 没有行被插入到我的ExtractsErrorLog表中。
TSQL的TRY...CATCH
不会捕获该错误。此错误属于“编译/重新编译”类型的错误,它不会由“在相同执行级别内”的CATCH
块来处理。
从MSDN:
-
编译:
以下类型的错误时 它们出现在相同的水平执行的作为TRY ... CATCH构造不是由CATCH块处理错误(例如语法错误)会阻止 批处理运行。编译后发生
错误中语句级重新编译发生,例如 作为对象名解析错误,因为延迟名称解析
的 ...
你可以使用TRY ... CATCH来处理编译期间发生的错误 或通过执行错误生成进行语句级重新编译代码在TRY块内的单独批处理中。例如,您通过将代码放入存储过程中或通过使用sp_executesql执行动态Transact-SQL语句来执行 。这允许 TRY ... CATCH捕获错误发生时的执行级别高于 。例如,以下代码显示存储的 过程,该过程会生成对象名称解析错误。包含TRY ... CATCH结构的批次 在存储过程的更高级别 处执行;并且发生在较低的 级别的错误被捕获。
我遇到了类似的问题与脚本创建TRY...CATCH
内部事务,如果失败,将ROLLBACK
交易。交易内部的一个声明抛出了相同的错误,并导致交易永不结束,因为从未输入过CATCH
。
正如在MSDN文章中提到的,一种替代方法是从INSERT
语句中创建一个存储过程,然后在try/catch中调用该过程。如果存储过程错误,您将在尝试创建时收到编译错误。如果表定义后来更改为使存储过程无效,那么TRY...CATCH
将为您捕获异常。
如果您希望它全部生活在一个脚本中,您可以将其设置为temporary stored procedure,但在创建sprocs时需要处理编译错误。这不是很漂亮,但它会工作:
-- Creating error sproc to re-use code
CREATE PROCEDURE #HandleError AS
Insert Into ExtractsErrorLog
SELECT GETDATE() as ErrorDate
,object_name(@@procid) as ProcedureName
,ERROR_NUMBER() as ErrorNumber
,ERROR_LINE() as ErrorLine
,ERROR_MESSAGE() as ErrorMessage;
DECLARE @errormessage as varchar(max);
DECLARE @errorseverity as int;
DECLARE @errorstate as int;
set @errormessage = ERROR_MESSAGE();
set @errorseverity = ERROR_SEVERITY();
set @errorstate = ERROR_STATE();
RAISERROR (@errormessage,
@errorseverity,
@errorstate);
GO
-- Create a stored procedure of our INSERT and catch any compilation errors
CREATE PROCEDURE #TEST AS
insert into tbl_X
select * from #temp_tbl_Y
GO
IF (@@ERROR <> 0) BEGIN
exeC#HandleError
-- If there was an error creating the sprocs, don't continue to the next batch
RETURN
END
-- If compilation succeeded, then run the sproc
BEGIN TRY
exeC#TEST
RETURN
END TRY
BEGIN CATCH
exeC#HandleError
END CATCH;
这是您的RETURN:“无条件退出查询或过程.RETURN是即时且完整的,可用于任何点退出过程,批处理或语句块。
'RETURN'没有被达到,如''所提供的值的列名或数量与表定义不匹配。“'错误... – 2013-02-26 19:10:54
谢谢拉塞尔 - 尽管我同意迈克尔,我很公平某些回报未达到。 感谢所有人对此的帮助 - 我想伊万有上面的答案。 – DanBennett 2013-02-27 11:24:32
这是一个编译时错误,请参阅本:http://stackoverflow.com/questions/7286667/sql-try-catch-statement-not-handling-error- sql-server-2008 – 2013-02-26 15:24:15
你可以发布'ExtractsErrorLog'的表定义吗? – Lamak 2013-02-26 16:07:34
感谢Ivan - 这很有道理 - 并且该线程也提供了一种解决方法。对不起,错过了它并转贴。我读过这个catch没有捕获编译 - 但我没有扭转,这将是一个编译错误。 有谁知道是否有一个在线指南,了解编译/重新编译时会出现什么错误。我可以明白为什么这会是一个现在,我想也缺少表等?但我想确定一下,我没有太多的细节。 – DanBennett 2013-02-27 11:20:35