输出参数值根据错误类型而变化

时间:2018-02-02 10:46:18

标签: sql-server

我有一个带有输出参数的存储过程。在我的过程中,我有两行有错误,根据引发的错误,输出参数的值是不同的。帮助我理解输出参数的这种行为。

以下是示例:

CREATE PROC SP (@p1 int OUTPUT) AS
BEGIN
 SET @p1 = @p1 + 10;
 select 5/0 
END
go



DECLARE @v int;
SET @v = 1;
EXEC SP @v OUTPUT;
PRINT @v;
go
--------------------------------

结果是11

CREATE PROC SP (@p1 int OUTPUT) AS
BEGIN
 SET @p1 = @p1 + 10;
 SELECT * FROM nonExistentTable; 
END
go


DECLARE @v int;
SET @v = 1;
EXEC SP @v OUTPUT;
PRINT @v;
go
--------------------------------

结果是1

1 个答案:

答案 0 :(得分:3)

我已经经历了几次这个答案的迭代,因为我已经发现了更多。我想我现在得出结论了。

正如OP指出的那样,更新参数的不返回是因为OUTPUT参数的复制/复制输出操作。但是,我发现一个不存在的表错误似乎不会被SP内部的TRY-CATCH拾取,而是被外面的TRY-CATCH捕获。

以下是第二个示例的修订版,使用TRY..CATCH来确定错误的获取位置。

我使用此代码运行SP的所有变体:

DECLARE @v int, @result int = 0, @Flag int = 1;
SET @v = 1;
BEGIN TRY
    SET @Flag = 2;
    EXEC @Result = SP @v OUTPUT;
    SET @Flag = 3;
END TRY
BEGIN CATCH
    PRINT ' C:   @Flag=' + CAST( @Flag AS Varchar(10) );

    SET @Flag = 4;

END CATCH

PRINT  ' D:      @v=' + CAST( @v AS Varchar(10) );
PRINT  ' E: @Result=' + CAST( @Result AS Varchar(10) );
PRINT  ' F:   @Flag=' + CAST( @Flag AS Varchar(10) );

SP的第一个版本是:

ALTER PROC SP (@p1 int OUTPUT) AS
BEGIN

    PRINT '>> SP';

    SET @p1 = @p1 + 10;

    PRINT '  A: @p1=' + CAST( @P1 as varchar(10) );

    BEGIN

        BEGIN TRY

             SELECT * FROM nonExistentTable; 
        END TRY
        BEGIN CATCH
            SET @p1 = 999;
            RETURN 22;
        END CATCH;  

        RETURN 399;

    END

    PRINT '  B: @p1=' + CAST( @P1 as varchar(10) );

    PRINT '<< SP';

END

输出结果为:

>> SP
  A: @p1=11
  C:   @Flag=2
  D:      @v=1
  E: @Result=0
  F:   @Flag=4

因此,即使在SP内更新输出参数@ p1,参数的值也不会传递回调用者。不存在的表错误不会被SP内部的TRY-CATCH 捕获,并且会绕过对OUTPUT参数的任何更新,但它会被TRY-CATCH 捕获 SP。

现在,经过测试,我在SP中添加了一些额外的代码:

ALTER PROC SP (@p1 int OUTPUT) AS
BEGIN

    PRINT '>> SP';

    SET @p1 = @p1 + 10;

    PRINT '  A: @p1=' + CAST( @P1 as varchar(10) );

    IF (EXISTS (SELECT * 
             FROM INFORMATION_SCHEMA.TABLES 
             WHERE TABLE_SCHEMA = 'dbo' 
             AND  TABLE_NAME = 'nonExistentTable'))

    BEGIN

        BEGIN TRY

             SELECT * FROM nonExistentTable; 
        END TRY
        BEGIN CATCH
            SET @p1 = 999;
            RETURN 22;
        END CATCH;  

        RETURN 399;

    END

    PRINT '  B: @p1=' + CAST( @P1 as varchar(10) );

    PRINT '<< SP';

END

有了这个结果:

>> SP
  A: @p1=11
  B: @p1=11
<< SP
 D:      @v=11
 E: @Result=0
 F:   @Flag=3

这很有趣。所以我再次更改了SP,这一次从我知道包含数据的表中选择行:

ALTER PROC SP (@p1 int OUTPUT) AS
BEGIN

    PRINT '>> SP';

    SET @p1 = @p1 + 10;

    PRINT '  A: @p1=' + CAST( @P1 as varchar(10) );

    IF EXISTS( SELECT * FROM Data_Table )
    BEGIN

        BEGIN TRY

             SELECT * FROM nonExistentTable; 
        END TRY
        BEGIN CATCH
            SET @p1 = 999;
            RETURN 22;
        END CATCH;  

        RETURN 399;

    END

    PRINT '  B: @p1=' + CAST( @P1 as varchar(10) );

    PRINT '<< SP';

END

在这种情况下,结果是:

>> SP
  A: @p1=11
 C:   @Flag=2
 D:      @v=1
 E: @Result=0
 F:   @Flag=4

最后检查一个完全不相关的表为空:

ALTER PROC SP (@p1 int OUTPUT) AS
BEGIN

    PRINT '>> SP';

    SET @p1 = @p1 + 10;

    PRINT '  A: @p1=' + CAST( @P1 as varchar(10) );

    IF EXISTS( SELECT * FROM Empty_Table )
    BEGIN

        BEGIN TRY

             SELECT * FROM nonExistentTable; 
        END TRY
        BEGIN CATCH
            SET @p1 = 999;
            RETURN 22;
        END CATCH;  

        RETURN 399;

    END

    PRINT '  B: @p1=' + CAST( @P1 as varchar(10) );

    PRINT '<< SP';

END

结果:

>> SP
  A: @p1=11
  B: @p1=11
<< SP
 D:      @v=11
 E: @Result=0
 F:   @Flag=3

有更多了解SQL Server内部工作原理的人可能能够解释这些结果并证明这些结果的合理性。