尝试和抓住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表中。

+2

这是一个编译时错误,请参阅本:http://stackoverflow.com/questions/7286667/sql-try-catch-statement-not-handling-error- sql-server-2008 – 2013-02-26 15:24:15

+0

你可以发布'ExtractsErrorLog'的表定义吗? – Lamak 2013-02-26 16:07:34

+0

感谢Ivan - 这很有道理 - 并且该线程也提供了一种解决方法。对不起,错过了它并转贴。我读过这个catch没有捕获编译 - 但我没有扭转,这将是一个编译错误。 有谁知道是否有一个在线指南,了解编译/重新编译时会出现什么错误。我可以明白为什么这会是一个现在,我想也缺少表等?但我想确定一下,我没有太多的细节。 – DanBennett 2013-02-27 11:20:35

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是即时且完整的,可用于任何点退出过程,批处理或语句块。

+0

'RETURN'没有被达到,如''所提供的值的列名或数量与表定义不匹配。“'错误... – 2013-02-26 19:10:54

+0

谢谢拉塞尔 - 尽管我同意迈克尔,我很公平某些回报未达到。 感谢所有人对此的帮助 - 我想伊万有上面的答案。 – DanBennett 2013-02-27 11:24:32