存储过程中可以有可选的 OUTPUT 参数吗?

发布于 2024-09-10 09:09:29 字数 647 浏览 10 评论 0原文

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

表/数据对象:

人员

Id
Name
Address

姓名

Id
FirstName
LastName

地址

Id
Country
City

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

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

过程或函数“Person_InsertPerson”需要参数 未提供“@AddressId”。

I have a stored procedure that has a bunch of input and output parameters because it is Inserting values to multiple tables. In some cases the stored proc only inserts to a single table (depending on the input parameters). Here is a mocked up scenario to illustrate.

Tables / Data Objects:

Person

Id
Name
Address

Name

Id
FirstName
LastName

Address

Id
Country
City

Say I have a stored procedure that inserts a person. If the address doesn't exist I won't add it to the Address table in the database.

Thus when I generate the code to call the stored procedure I don't want to bother adding the Address parameter. For INPUT parameters this is ok because SQL Server allows me to supply default values. But for the OUTPUT parameter what do I do in the stored procedure to make it optional so I do not receive an error...

Procedure or function 'Person_InsertPerson' expects parameter
'@AddressId', which was not supplied.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

背叛残局 2024-09-17 09:09:29

输入和输出参数都可以指定默认值。在这个例子中:

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

Both input and output parameters can be assigned defaults. In this example:

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

the first paramter is required, and the second and third are optional--if not set by the calling routine, they will be assigned the default values. Try messing around with it and the following test-call routine in SSMS using different values and settings to see how it all works together.

DECLARE @Output int

SET @Output = 3

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

PRINT '---------'
PRINT @Output
泪意 2024-09-17 09:09:29

输出参数和默认值不能很好地协同工作!这是来自 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 的目的。

恕我直言,这个功能组合是一个可疑的构造,我认为代码味道(唷!!)

Output parameters and default values do not work well together! This is from SQL 10.50.1617 (2008 R2). Do not be fooled into believing this construct magically does a SET to that value on your behalf (like my co-worker did)!

This "toy" SP interrogates the OUTPUT parameter value, whether it is the default value or 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

If you send in an uninitialized value (i.e. NULL) for the OUTPUT, you really got NULL inside the SP, and not 0. Makes sense, something got passed for that parameter.

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

output is:

wtf its NULL
@QR=NULL

If we add an explicit SET from the caller we get:

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

and the (unsurprising) output:

@QR=999

Again, makes sense, a parameter is passed, and SP took no explicit action to SET a value.

Add a SET of the OUTPUT parameter in the SP (like you're supposed to do), but do not set anything from the caller:

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

Now when executed:

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

the output is:

wtf its NULL
@QR=1234

This is the "standard" behavior for OUTPUT parameter handling in SPs.

Now for the plot twist: The only way to get the default value to "activate", is to not pass the OUTPUT parameter at all, which IMHO makes little sense: since it's set up as an OUTPUT parameter, that would mean returning something "important" that should be collected.

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

gives this output:

yay its zero
@QR=NULL

But this fails to capture the SPs output, presumably the purpose of that SP to begin with.

IMHO this feature combination is a dubious construct I would consider a code smell (phew!!)

眼角的笑意。 2024-09-17 09:09:29

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

@AddressId int = -1 Output

由于 AddressId 严格用作 OUTPUT< /代码> 变量。但它有效。如果您有更好的解决方案,请告诉我。

Looks like I can just add a default value to the OUTPUT parameter such as:

@AddressId int = -1 Output

Seems like its poor in terms of readability since AddressId is intended strictly as an OUTPUT variable. But it works. Please let me know if you have a better solution.

早乙女 2024-09-17 09:09:29

补充一下 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)

Adding on to what Philip said:

I had a stored procedure in my sql server database that looked like the following:

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

And I was calling it from my .net code as the following:

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

I was getting an System.Data.SqlClient.SqlException: Procedure or function expects parameter '@current_phase', which was not supplied.

I am also using this function somewhere else in my program and passing in a parameter and handling the output one. So that I didn't have to modify the current call I was making I just changed the stored procedure to make the output parameter also optional.

So it now looks as the following:

dbo.<storedProcedure>
(@current_user char(8) = NULL,
@current_phase char(3) = NULL OUTPUT)
谁人与我共长歌 2024-09-17 09:09:29

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

cmd.CommandType = CommandType.StoredProcedure;

取自 此处

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

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

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

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

Since you are executing a stored procedure and not a SQL statement, you have to set the command type of your SQL Command to Stored Procedure:

cmd.CommandType = CommandType.StoredProcedure;

Taken from here.

Also, once you get that error removed, you can use SQL's nvl() function in your procedure to specify what you want displayed when a NULL value is encountered.

Sorry about not properly addressing the question...must have misunderstood you. Here's an example of nvl, which I think might address it a little better?

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

The SQL statement above would return 'n/a' if the supplier_city field contained a null value. Otherwise, it would return the supplier_city value.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文