我可以在存储过程中使用可选的OUTPUT参数吗?
我有一个存储过程有一堆input和输出参数,因为它是插入值到多个表。 在某些情况下,存储的proc只能插入到一个表(取决于input参数)。 这是一个嘲弄的场景来说明。
表/数据对象:
人
Id Name Address
名称
Id FirstName LastName
地址
Id Country City
说我有一个插入一个人的存储过程。 如果地址不存在,我不会将其添加到数据库中的Address
表中。
因此,当我生成的代码来调用存储过程,我不想打扰添加Address
参数。 对于INPUT
参数,这是可以的,因为SQL Server允许我提供默认值。 但是对于OUTPUT
参数我该怎么做在存储过程,使其可选,所以我没有收到错误…
过程或函数'Person_InsertPerson'需要参数'@AddressId',它没有提供。
input和输出参数都可以分配为默认值。 在这个例子中:
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中的以下testing调用例程,以了解它们如何一起工作。
DECLARE @Output int SET @Output = 3 EXECUTE MyTest @Data1 = 1 ,@Data2 = 2 ,@Data3 = @Output output PRINT '---------' PRINT @Output
输出参数和默认值不能很好地一起工作! 这是从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
如果你为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中添加一个OUTPUT
参数的SET
(就像你应该做的那样),但是不要设置来自调用者的任何东西:
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开始的目的。
恕我直言,这个function组合是一个可疑的构造,我会考虑一个代码气味 (唷!!)
看起来像我可以添加一个默认值的OUTPUT
参数,如:
@AddressId int = -1 Output
由于AddressId
严格意义上是一个OUTPUT
variables,因此在可读性方面似乎很差。 但它的作品。 请让我知道,如果你有一个更好的解决scheme。
加上菲利普所说的话:
我在我的sql服务器数据库中有一个存储过程,如下所示:
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)
由于您正在执行存储过程而不是SQL语句,因此必须将SQL命令的命令types设置为存储过程:
cmd.CommandType = CommandType.StoredProcedure;
从这里采取。
另外,一旦你清除了这个错误,你可以在你的过程中使用SQL的nvl()
函数来指定当遇到NULL值时你想要显示的内容。
对不起,没有妥善处理这个问题…一定是误解了你。 这里有一个nvl的例子,我认为可能会更好一点呢?
select NVL(supplier_city, 'n/a') from suppliers;
如果supplier_city
字段包含空值,则上面的SQL语句将返回'n / a'。 否则,它将返回supplier_city
值。