我有一个带有输出参数的存储过程。在我的过程中,我有两行有错误,根据引发的错误,输出参数的值是不同的。帮助我理解输出参数的这种行为。
以下是示例:
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
答案 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内部工作原理的人可能能够解释这些结果并证明这些结果的合理性。