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

Jus*_*tin 69 sql-server stored-procedures data-access

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

表/数据对象:

Id
Name
Address
Run Code Online (Sandbox Code Playgroud)

名称

Id
FirstName
LastName
Run Code Online (Sandbox Code Playgroud)

地址

Id
Country
City
Run Code Online (Sandbox Code Playgroud)

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

因此,当我生成调用存储过程的代码时,我不想打扰添加Address参数.对于INPUT参数,这是可以的,因为SQL Server允许我提供默认值.但是对于OUTPUT参数我在存储过程中做什么使它成为可选的,所以我没有收到错误...

过程或函数'Person_InsertPerson'需要参数'@AddressId',这是未提供的.

Phi*_*ley 108

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

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
Run Code Online (Sandbox Code Playgroud)

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

DECLARE @Output int

SET @Output = 3

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

PRINT '---------'
PRINT @Output
Run Code Online (Sandbox Code Playgroud)

  • 谢谢!我想知道为什么我不能使用`@var INT OUTPUT = NULL` - 语法令人困惑. (2认同)
  • 并不会真正调用默认值(您设置为@output),默认值仅在您不传递任何内容时才激活,请参见我的答案以获取完整处理。 (2认同)

esc*_*llc 13

输出参数和默认值不能很好地协同工作!这来自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
Run Code Online (Sandbox Code Playgroud)

如果你发送了一个未初始化的值(即NULL)OUTPUT,你真的NULL进入了SP,而不是0.有道理,为该参数传递了一些东西.

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

输出是:

wtf its NULL
@QR=NULL
Run Code Online (Sandbox Code Playgroud)

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

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

和(不足为奇的)输出:

@QR=999
Run Code Online (Sandbox Code Playgroud)

同样,有意义的是,传递了一个参数,并且SP没有对SET值进行任何显式操作.

添加SET了的OUTPUT参数在SP(像你应该做的),但是没有设置从呼叫者什么:

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
Run Code Online (Sandbox Code Playgroud)

现在执行时:

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

输出是:

wtf its NULL
@QR=1234
Run Code Online (Sandbox Code Playgroud)

这是OUTPUTSP中参数处理的"标准"行为.

现在对于情节扭曲:获取默认值为"激活"的唯一方法是根本不传递OUTPUT参数,恕我直言就没有意义:因为它被设置为OUTPUT参数,这意味着返回"重要"的东西应该收集.

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

给出这个输出:

yay its zero
@QR=NULL
Run Code Online (Sandbox Code Playgroud)

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

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

  • 嗯,顺便说一下,可选输入参数也是如此。输出参数没有什么特别的。如果显式传递带有 NULL 值的参数,则该值不会被参数的默认值覆盖。我不明白为什么这是一些意想不到的陷阱,这是有记录的、预期的行为。 (4认同)
  • @ruffin没有优势;可选的OUTPUT参数不能按每个人的预期工作,这就是为什么我建立了这个答案。 (2认同)

Jus*_*tin 5

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

@AddressId int = -1 Output
Run Code Online (Sandbox Code Playgroud)

看起来它的可读性很差,因为AddressId它严格地作为一个OUTPUT变量。但它有效。如果您有更好的解决方案,请告诉我。