我可以在存储过程中使用可选的OUTPUT参数吗?

时间:2010-07-16 17:47:35

标签: sql-server stored-procedures data-access

我有一个存储过程,它有一堆输入和输出参数,因为它是将值插入多个表。在某些情况下,存储过程仅插入到单个表中(取决于输入参数)。这是一个模拟的场景来说明。

表/数据对象:

Id
Name
Address

命名

Id
FirstName
LastName

地址

Id
Country
City

假设我有一个插入人的存储过程。如果该地址不存在,我将不会将其添加到数据库中的Address表。

因此,当我生成调用存储过程的代码时,我不想费心添加Address参数。对于INPUT参数,这是可以的,因为SQL Server允许我提供默认值。但对于OUTPUT参数,我该如何在存储过程中使其成为可选项,以便我不会收到错误...

  

过程或函数'Person_InsertPerson'需要参数   '@ AddressId',未提供。

5 个答案:

答案 0 :(得分:103)

可以为输入和输出参数分配默认值。在这个例子中:

CREATE PROCEDURE MyTest
  @Data1 int
 ,@Data2 int = 0
 ,@Data3 int = null output

AS

PRINT @Data1
PRINT @Data2
PRINT isnull(@Data3, -1)

SET @Data3 = @Data3 + 1

RETURN 0

第一个参数是必需的,第二个和第三个参数是可选的 - 如果没有被调用例程设置,它们将被分配默认值。尝试使用不同的值和设置来解决SSMS中的以及以下测试调用例程,以了解它们如何一起工作。

DECLARE @Output int

SET @Output = 3

EXECUTE MyTest
  @Data1 = 1
 ,@Data2 = 2
 ,@Data3 = @Output output

PRINT '---------'
PRINT @Output

答案 1 :(得分:12)

输出参数和默认值不能很好地协同工作!这来自SQL 10.50.1617(2008 R2)。 不要被愚弄相信这个构造神奇地为你代表SET代价(就像我的同事一样)!

此“玩具”SP会询问OUTPUT参数值,无论是默认值还是NULL

CREATE PROCEDURE [dbo].[omgwtf] (@Qty INT, @QtyRetrieved INT = 0 OUTPUT)
AS
IF @QtyRetrieved = 0
BEGIN
    print 'yay its zero'
END
IF @QtyRetrieved is null
BEGIN
    print 'wtf its NULL'
END
RETURN

如果您为NULL发送未初始化的值(即OUTPUT),则您在SP内部确实有NULL,而不是0。有道理,该参数传递了一些东西。

declare @QR int
exec [dbo].[omgwtf] 1, @QR output
print '@QR=' + coalesce(convert(varchar, @QR),'NULL')

输出是:

wtf its NULL
@QR=NULL

如果我们从调用者添加显式SET,我们会得到:

declare @QR int
set @QR = 999
exec [dbo].[omgwtf] 1, @QR output
print '@QR=' + coalesce(convert(varchar, @QR),'NULL')

和(不足为奇的)输出:

@QR=999

同样,有意义的是,传递了一个参数,而SP没有对SET值进行明确的操作。

在SP中添加SET OUTPUT参数(就像你应该这样做),但不要从调用者那里设置任何内容:

ALTER PROCEDURE [dbo].[omgwtf] (@Qty INT, @QtyRetrieved INT = 0 OUTPUT)
AS
IF @QtyRetrieved = 0
BEGIN
    print 'yay its zero'
END
IF @QtyRetrieved is null
BEGIN
    print 'wtf its NULL'
END
SET @QtyRetrieved = @Qty
RETURN

现在执行时:

declare @QR int
exec [dbo].[omgwtf] 1234, @QR output
print '@QR=' + coalesce(convert(varchar, @QR),'NULL')

输出是:

wtf its NULL
@QR=1234

这是SP中OUTPUT参数处理的“标准”行为。

现在对于情节扭曲:获取默认值“激活”的唯一方法是不会传递OUTPUT参数,恕我直言的意义不大:因为它被设置为OUTPUT参数,这意味着返回应该收集的“重要”内容。

declare @QR int
exec [dbo].[omgwtf] 1
print '@QR=' + coalesce(convert(varchar, @QR),'NULL')

给出了这个输出:

yay its zero
@QR=NULL

但是这无法捕获SP的输出,可能是该SP开始的目的。

恕我直言这个功能组合是一个可疑的构造我会考虑代码气味(p !!)

答案 2 :(得分:4)

看起来我可以在OUTPUT参数中添加默认值,例如:

@AddressId int = -1 Output

在可读性方面似乎很差,因为AddressId严格意图为OUTPUT变量。但它的确有效。如果您有更好的解决方案,请告诉我。

答案 3 :(得分:1)

由于您正在执行存储过程而不是SQL语句,因此必须将SQL命令的命令类型设置为存储过程:

cmd.CommandType = CommandType.StoredProcedure;

取自here

此外,一旦删除了该错误,您可以在过程中使用SQL的nvl()函数来指定遇到NULL值时要显示的内容。

很抱歉没有正确解决这个问题......一定是误解了你。这是一个nvl的例子,我认为可能会更好地解决它?

select NVL(supplier_city, 'n/a')
from suppliers;

如果supplier_city字段包含空值,则上面的SQL语句将返回'n / a'。否则,它将返回supplier_city值。

答案 4 :(得分:1)

加上菲利普所说的话:

我的sql server数据库中有一个存储过程,如下所示:

dbo.<storedProcedure>
(@current_user char(8) = NULL,
@current_phase char(3) OUTPUT)

我从我的.net代码中调用它如下:

 DataTable dt = SqlClient.ExecuteDataTable(<connectionString>, <storedProcedure>);

我收到一个System.Data.SqlClient.SqlException:过程或函数需要参数'@current_phase',这是未提供的。

我也在我的程序中的其他地方使用此函数并传入参数并处理输出。所以我没有必要修改当前调用我正在改变存储过程以使输出参数也是可选的。

现在看起来如下:

dbo.<storedProcedure>
(@current_user char(8) = NULL,
@current_phase char(3) = NULL OUTPUT)