SQL Server 的 try-catch 内部异常信息难题

9
下面的SQL语句是一个很好的例子,它会抛出一个带有嵌套细节的异常。在catch部分中,我只能获得外部异常信息Could not create constraint. See previous errors(没有太大用处!)。我想要得到内部异常消息:

引入FOREIGN KEY约束“FK_TWO”到表“TABLE2”可能会导致循环或多个级联路径。指定ON DELETE NO ACTION或ON UPDATE NO ACTION,或修改其他FOREIGN KEY约束(您可以在不使用try-catch运行代码来获取此消息)。

在Catch块中,如何在T-SQL中实现这一点?

BEGIN TRY
      BEGIN TRAN;

        CREATE TABLE TABLE1 (USER_ID INTEGER NOT NULL PRIMARY KEY, USER_NAME
            CHAR(50) NOT NULL);

        CREATE TABLE TABLE2 (AUTHOR_ID INTEGER NOT NULL PRIMARY KEY, AUTHOR_NAME
            CHAR(50) NOT NULL, LASTMODIFIEDBY INTEGER NOT NULL, ADDEDBY INTEGER NOT
            NULL);

        ALTER TABLE TABLE2 ADD CONSTRAINT FK_ONE FOREIGN KEY (LASTMODIFIEDBY)
            REFERENCES TABLE1 (USER_ID) ON DELETE CASCADE ON UPDATE CASCADE;

        ALTER TABLE TABLE2 ADD CONSTRAINT FK_TWO FOREIGN KEY (ADDEDBY)
            REFERENCES TABLE1(USER_ID) ON DELETE NO ACTION ON UPDATE CASCADE;   

        COMMIT TRAN;
END TRY
BEGIN CATCH

      DECLARE @ERROR_MSG NVARCHAR(MAX), @SEVERITY INT, @STATE INT
      SELECT @SEVERITY = ERROR_SEVERITY(), @STATE = ERROR_STATE()
            , @ERROR_MSG = ERROR_MESSAGE() + ' err src line: ' + CAST( ERROR_LINE() AS NVARCHAR(20)) + ' ' + ISNULL(ERROR_PROCEDURE(), ''); 

      ROLLBACK;
      -- RE-THROW EXCEPTION FOR DIAGNOSTIC VISIBILITY
      RAISERROR (@ERROR_MSG ,@SEVERITY, @STATE); 
END CATCH;

[编辑]

经过多次搜索,似乎没有解决此问题的方法。希望他们能在未来的版本中修复这个问题。


2
我认为没有任何方法可以做到这一点。另请参阅相关问题:从单个语句中捕获多个错误消息 - Joe Stefanelli
2个回答

10

你不能重新抛出原始错误。你必须抛出一个新的错误,错误编号超过50000,其中包含捕获到的错误消息。参见异常处理和嵌套事务中的示例:

begin catch
    declare @error int, @message varchar(4000), @xstate int;
    select @error = ERROR_NUMBER()
        , @message = ERROR_MESSAGE();
raiserror ('Caught exception: %d: %s', 16, 1, @error, @message) ;
return;
end catch   
我提供的链接中有一个更详细的示例,还涵盖了强制执行 XACT_STATE() 检查以及将 try/catch 块与事务语义混合使用的情况。
在下一个版本(“Denali”)中,这个问题得到了解决,因为你可以发出一个不带参数的 throw;,像其他 try/catch 语言一样引发原始异常。请参阅 TRY CATCH THROW: T-SQL 中的错误处理变化 更新 哎呀,我有点斜读这篇文章。如果有更多的异常被引发,则只能捕获其中一个异常。这一点在 Denali 中仍然是正确的。但大多数情况下引发的异常的严重性为 0(意味着它们实际上只是打印信息,而不是异常),它们会作为信息消息传递到客户端(SqlConnection.InfoMessage 事件)。

1

目前还没有解决这个问题的方法。根据this,下一个版本的SQL Server的解决方案将是使用新的throw关键字,它将重新引发两个错误。


如果你愿意深入解析输出缓冲区,可能会有解决方案! - Martin Smith

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接