除非指定了自定义错误消息,否则 THROW 不包括调用过程的名称

kry*_*tah 7 sql-server t-sql sql-server-2012

我正在经历一些THROW我无法理解的行为。考虑以下存储过程:

CREATE PROCEDURE usp_division_err AS 
SET NOCOUNT ON;
BEGIN TRY
    EXEC('select 1/0')
END TRY
BEGIN CATCH
    THROW;
END CATCH 
Run Code Online (Sandbox Code Playgroud)

执行该过程时,会引发以下错误:

消息 8134,级别 16,状态 1,第 1 行
遇到除以零错误。

请注意,没有包含有关在哪个过程中引发错误的信息。那是因为错误的动态 SQL 在另一个作用域中执行,这很好。但是,将CATCH-block更改为如下所示

BEGIN CATCH
    THROW 50000, 'An error occurred.', 1;
END CATCH 
Run Code Online (Sandbox Code Playgroud)

并且该过程的执行将引发此错误:

Msg 50000, Level 16, State 1, Procedure usp_division_err, Line 7 [Batch Start Line 0]
发生错误。

执行动态SQL时仍然遇到错误,但是当我手动指定错误号和错误消息( 的第一个和第二个参数THROW)时,不知何故出现了执行过程的procedure-name。

为什么过程名称出现在第二个错误消息中而不是第一个错误消息中?

Han*_*non 3

代码CATCH如下:

BEGIN CATCH
    DECLARE @msg nvarchar(4000) = ERROR_MESSAGE()
    DECLARE @errno int = 50000 + ERROR_NUMBER();
    DECLARE @state int = ERROR_STATE();
    THROW @errno, @msg, @state;
END CATCH 
Run Code Online (Sandbox Code Playgroud)

这允许您将所有参数传递到THROW语句中,以便它可以将它们发送回调用者。

我这样测试过:

USE tempdb;
IF OBJECT_ID('dbo.usp_division_err', 'P') IS NOT NULL 
DROP PROCEDURE dbo.usp_division_err;
GO
CREATE PROCEDURE dbo.usp_division_err AS 
SET NOCOUNT ON;
BEGIN TRY
    EXEC('select 1/0');
END TRY
BEGIN CATCH
    DECLARE @msg nvarchar(4000) = ERROR_MESSAGE()
    DECLARE @errno int = 50000 + ERROR_NUMBER();
    DECLARE @state int = ERROR_STATE();
    THROW @errno, @msg, @state;
END CATCH 
GO
EXEC dbo.usp_division_err;
Run Code Online (Sandbox Code Playgroud)

结果:

消息 58134,级别 16,状态 1,过程 dbo.usp_division_err,第 10 行 [批处理开始第 16 行]
遇到除以零错误。

要获得本机错误编号,您只需从报告的错误编号中减去 50000。由于 的参数THROW是可选的,因此 内部必须有两个代码路径THROW,一个报告过程名称,另一个则不报告。我将让读者决定哪个代码路径可以做到这一点。