首页 文章

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

提问于
浏览
64

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

表/数据对象:

Person

Id
Name
Address

Name

Id
FirstName
LastName

Address

Id
Country
City

假设我有一个插入人的存储过程 . 如果地址没有't exist I won' t将其添加到数据库中的 Address 表 .

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

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

5 回答

  • 1

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

    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
    
  • 4

    输出参数和默认值不能很好地协同工作!这来自SQL 10.50.1617(2008 R2) . 不要被愚弄相信这个结构神奇地代表你做了这个 Value (就像我的同事那样)!

    无论是默认值还是 NULL ,"toy" SP都会询问 OUTPUT 参数值 .

    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
    

    如果你为 OUTPUT 发送了一个未初始化的值(即 NULL ),你真的在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中添加 OUTPUTOUTPUT 参数(就像你应该这样做),但是不要从调用者那里设置任何东西:

    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 参数处理的"standard"行为 .

    现在对于 plot twist :获取默认值为"activate"的唯一方法是 not pass the OUTPUT parameter at all ,恕我直言,因为它被设置为 OUTPUT 参数,这意味着返回应收集的东西"important" .

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

    给出这个输出:

    yay its zero
    @QR=NULL
    

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

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

  • 1

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

    @AddressId int = -1 Output
    

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

  • 11

    加上Philip说的话:

    我的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)
    
  • 102

    由于您正在执行存储过程而不是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 值 .

相关问题