Sql server 在TSQL上尝试捕获-捕获未捕获

Sql server 在TSQL上尝试捕获-捕获未捕获,sql-server,sql-server-2008,tsql,try-catch,Sql Server,Sql Server 2008,Tsql,Try Catch,我有一个存储过程,它似乎没有正确地记录错误 代码出错,但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_

我有一个存储过程,它似乎没有正确地记录错误

代码出错,但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;
进程失败的错误是我们的老朋友 “提供的值的列名或数目与表定义不匹配。”
我已经修复了这个错误-这是一个愚蠢的懒惰错误-但我很困惑为什么我的错误日志记录过程似乎没有工作-没有任何行被插入到我的ExtractErrorLog表中。

这是您的返回:“无条件退出查询或过程。RETURN是即时且完整的,可以在任何时候用于从过程、批处理或语句块中退出。“

TSQL的
TRY…CATCH
不会捕获该错误。该错误属于“编译/重新编译”类型的错误,而
CATCH
块“在同一执行级别内”不会处理该错误。”

发件人:

以下类型的错误不由CATCH块处理: 它们发生在与TRY…CATCH构造相同的执行级别:

  • 编译错误,如语法错误,会阻止批处理 跑步

  • 语句级重新编译期间发生的错误,例如 编译后发生的对象名称解析错误,因为 延迟名称解析的实现

您可以使用TRY…CATCH来处理编译期间发生的错误 或通过执行错误生成 在TRY块内的单独批处理中编写代码 这是通过将代码放入存储过程或执行 使用sp_executesql的动态Transact-SQL语句。这允许 TRY…CATCH以比 错误发生。例如,以下代码显示存储的 生成对象名称解析错误的过程。批处理 包含TRY…CATCH构造的正在更高级别上执行 比存储过程;以及错误,该错误以更低的速度发生 水平,被抓住了

我遇到了类似的问题,脚本在
TRY…CATCH
中创建了一个事务,如果事务失败,它将
回滚该事务。事务中的一条语句抛出了相同的错误,并导致该事务永远无法关闭,因为从未输入
CATCH

正如MSDN文章中提到的,一种替代方法是从
INSERT
语句中创建一个存储过程,然后在try/catch中调用它。如果存储过程出错,您将在尝试创建时捕获编译错误。如果稍后表定义更改为使存储过程无效,则
try…catch
将为您捕获异常

如果希望所有脚本都存在于一个脚本中,则可以将其设为一个脚本,但在创建存储过程时需要处理编译错误。这并不漂亮,但可以工作:

-- 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;
--创建错误存储过程以重复使用代码
创建过程#HandleError AS
插入到ExtractErrorLog中
选择GETDATE()作为ErrorDate
,对象名称(@@PROCEID)为ProcedureName
,ERROR_NUMBER()作为ErrorNumber
,ERROR_LINE()作为ErrorLine
,ERROR_MESSAGE()作为ErrorMessage;
将@errormessage声明为varchar(最大值);
将@errorseverity声明为int;
声明@errorstate为int;
设置@errormessage=ERROR_MESSAGE();
设置@errorseverity=ERROR_SEVERITY();
设置@errorstate=ERROR_STATE();
RAISERROR(@errormessage,
@错误严重性,
@错误状态);
去
--创建INSERT的存储过程并捕获任何编译错误
创建程序#测试为
插入tbl_X
从临时任务中选择*
去
如果(@@0错误)开始
执行官#HandleError
--如果创建存储过程时出错,请不要继续下一批
返回
结束
--如果编译成功,则运行存储过程
开始尝试
执行测试
返回
结束尝试
开始捕捉
执行官#HandleError
末端捕捉;

我在日志记录的INSERT语句之前使用了CATCH块中的THOW,并且遇到了与您相同的问题。一旦我在日志记录INSERT语句之后移动THOW,它就工作了。看起来THOW可能会终止会话


您在代码示例中不使用THROW,但认为这可能会帮助其他人。

这是一个编译时错误,请参见:您可以发布
extractersErrorLog的表定义吗?
?谢谢Ivan-这很有意义-该线程也提供了一个解决方法。很抱歉,错过了它并重新发布了。我读到catch没有捕获compile-但我没有意识到这会是一个编译错误。有人知道在线上有没有一个指南来了解编译/重新编译时会发生什么错误。我现在可以理解为什么会出现这种情况,我想也会丢失一些表等。但是我想确定一下,我没有太多关于这方面的详细信息。@DanBennett,你知道吗找到解决方法吗?我期待着这个错误,并希望尝试|捕获它以在它发生时运行不同的逻辑-解决方法只是将错误移动到内部SP调用。嗨@ColinMac-查看Ivan G消息中的链接,它指向资源,其中一些指向选项。我们最终没有这样做,因为我们觉得选项捕获错误增加了工时代码复杂性,这超过了好处。YMMV未达到
返回值
,如
“列名或提供的值数量与表定义不匹配所示。“
error…谢谢拉塞尔-虽然我同意迈克尔的观点,但我相当肯定没有收到回报。谢谢大家在这方面的帮助-我想Ivan已经有了上面的答案。所以基本上,如果一个对象被重命名为t