SQL Server 输出参数问题
Posted
技术标签:
【中文标题】SQL Server 输出参数问题【英文标题】:SQL Server output parameter issue 【发布时间】:2009-08-08 07:25:09 【问题描述】:我使用的是 SQL Server 2008 Enterprise。我正在学习 SQL Server 存储过程的 OUTPUT 参数。例如,存储过程 sp_add_jobschedule 有一个名为 schedule_id 的 OUTPUT 参数。
http://msdn.microsoft.com/en-us/library/ms366342.aspx
我的困惑是,看起来 OUTPUT 参数可以提供一个输入值并返回一个值,看起来它具有 INPUT 和 OUTPUT 参数的行为?是否允许不为 OUTPUT 参数提供任何 INPUT 值(使其看起来像纯输出参数行为)?
【问题讨论】:
【参考方案1】:这种混淆在一定程度上是有道理的——像 Oracle 这样的其他 RDBMS 确实有存储过程参数,这些参数可以是 IN
(仅输入)、OUT
(仅输出)或 INOUT
(两种方式 - “按引用传递”类型的参数)。
SQL Server 在这里有点草率,因为它将参数标记为OUTPUT
,但实际上,这意味着INPUT
/OUTPUT
- 它基本上只是意味着存储过程有机会从其返回一个值调用那个参数。
所以是的 - 即使它被称为 OUTPUT
参数,它实际上更像是一个 INPUT
/OUTPUT
参数,而那些 IN
、INOUT
、OUT
像 Oracle 中的那些在 SQL 中不存在服务器(在 T-SQL 中)。
【讨论】:
感谢 Marc,“这种混淆在一定程度上是有道理的——像 Oracle 这样的其他 RDBMS 确实有存储过程参数”——这就是我感到困惑的原因。我正在从 DB2 迁移到 SQL Server。很多概念都不一样。 :-( 还有一个问题,我们可以将OUTPUT参数作为可选参数,即我们不能提供它的输入值,而只是将其用作输出? 是的,当然 - 您可以提供 INPUT 值或将其留空 - 如果您不在存储过程中使用它,那么您传入的内容完全没有意义。这取决于您和代码无论您是否查看传入的值,您都可以在过程中写入。“OUTPUT”子句仅表示存储过程能够在此参数中返回值 - 仅此而已。 但是当我在 SSIS 中使用它时,OUT 就出来了,我真的希望 OUT 对 in 和 out 都适用。 @IrawanSoetomo 是的,我也刚刚意识到:SSIS 中的 OUTPUT 声明的参数的行为不像 SQL OUTPUT 参数(也不是 Oracle INOUT):参数传递到 T-SQL 为NULL 无论在调用时是什么。【参考方案2】:我可以给你一个简短的例子,说明如何使用输出参数创建存储过程。
CREATE PROCEDURE test_proc
@intInput int,
@intOutput int OUTPUT
AS
set @intOutput = @intInput + 1
go
要调用这个过程,然后使用输出参数,请执行以下操作:
declare @intResult int
exec test_proc 3 ,@intResult OUT
select @intResult
你看,你应该首先声明输出变量。执行存储过程后,输出值将在您的变量中。您可以为输出变量设置任何值,但在执行存储过程后,它将包含存储过程返回的确切值(无论输出变量中的值是什么)。
例如:
declare @intResult int
exec test_proc 3 ,@intResult OUT
select @intResult
它将返回 4。并且:
declare @intResult int
set @intResult = 8
exec test_proc 3 ,@intResult OUT
select @intResult
同样返回 4。
【讨论】:
谢谢,所以OUTPUT参数有输入参数和输出参数的行为? @George2:是的,OUTPUT 参数同时作为输入和输出参数。【参考方案3】:是的,您可以使用 OUTPUT 参数来传入和检索值(尽管目前我想不出这样做的充分理由)。
这里有一个简单的例子来证明这一点:
-- The stored procedure
CREATE PROCEDURE OutParamExample
@pNum int OUTPUT
AS
BEGIN
select @pNum
set @pNum = @pNum + 5
END
GO
-- use a local variable to retrieve your output param value
declare @TheNumber int
set @TheNumber = 10
print @TheNumber
exec OutParamExample @TheNumber OUTPUT
print @TheNumber
结果将如下所示:
10
-----------
10
(1 row(s) affected)
15
编辑:好的,我想我在第二段中遗漏了一个“不”,可能没有回答您提出的问题。如果你想要一个严格的输出参数(例如返回码之类的东西),你当然不必为作为输出参数传递的局部变量提供 value,但你仍然必须声明局部变量,这样您就可以在过程本身的范围之外访问返回的值。
例如:
declare @LocalNumber int
-- I don't have to assign a value to @LocalNumber to pass it as a parameter
exex OutParamExample @LocalNumber OUTPUT
-- (assume SP has been altered to assign some reasonable value)
-- but I do have to declare it as a local variable so I can get to
-- the return value after the stored procedure has been called
print @LocalNumber
【讨论】:
【参考方案4】:进一步补充上面其他人所说的,OUTPUT 参数可以充当 INPUT 以及 OUTPUT。但是,它依赖于存储过程来使用传递给它的值。
如果存储过程忽略了为 OUTPUT 参数传入的值(通常应该如此),则无论如何都会忽略 INPUT 值。
使用 Sergey 的代码,我可以使用用户为 @intOutput 传递的值(如果需要)
create PROCEDURE test_proc
@intInput int,
@intOutput int OUTPUT
AS
set @intOutput = @intOutput + 1
go
但是,这违背了 OUTPUT 参数的目的。 为了给出不同的观点,c# 编译器强制你通过赋值覆盖 out 参数的值(不使用输出参数)。
例如我不能在 c# 中做到这一点。这里它只作为输出参数(即忽略用户传递给这个函数的值)
static void dosomething(out int i)
//i = 0;
i = i + 1;
【讨论】:
【参考方案5】:问题是 - 为什么您要禁止提供输入?这没有任何意义。考虑这个简单的例子:
CREATE PROCEDURE test (@param AS INT OUTPUT) AS
BEGIN
SET @param = 100
END
GO
DECLARE @i INT
SET @i = 0
EXECUTE test @i OUTPUT
PRINT @i
DROP PROCEDURE test
打印出来
100
看看 - 如果你不把一个变量 in 首先放入,你应该如何获得一个值 out?
【讨论】:
谢谢Tomalak,我不确定我是否可以用这种方式设计一个带有输出参数的存储过程。我可以将输出参数作为可选输入参数(因为输出参数允许我们不输入任何值)和返回值? 我不确定这有什么难理解的。 :) 实际问题是什么? 我使用OUTPUT参数作为选项输入参数,不知道使用是否正确?我就是这样使用的,在存储过程中,我会检查调用者是否为OUTPUT参数输入了任何值,如果是,我会做一些事情,如果没有OUTPUT参数的输入值,我会做一些其他事情。 【参考方案6】:考虑在编程语言中通过引用传递的输出参数,它是相同的。我现在能想到的最好的例子是返回错误代码。你想要一些插入...如果你从 SP 中选择返回代码,你必须在你的代码中取回它,使用你没有的 OUTPUT 参数,它已经在你的参数中(我的意思是使用 C# 命令,php init 存储 proc 方法,或与构造字符串不同的东西)
【讨论】:
感谢 Svetlio,看起来它同时具有 INPUT 和 OUTPUT 参数的行为?是否允许不为 OUTPUT 参数提供任何 INPUT 值(使其看起来像纯输出参数行为)? @George2:“是否允许不为 OUTPUT 参数提供任何 INPUT 值(使其看起来像纯输出参数行为)” - 这不是 Sergey 在代码中显示的内容吗? 1 个? 你是说这个?声明@intResult int exec test_proc 3 ,@intResult OUT 选择@intResult【参考方案7】:关于原始问题的一部分的附加说明:
“OUTPUT参数(..)是否允许不提供任何INPUT值?”
在 SQLServer 中,可以为 OUTPUT 参数指定默认值(正如其他人指出的那样,实际上是 INOUT)。考虑以下示例,您可以在其中指定显式值或让函数本身生成 ID。
CREATE PROCEDURE test (@id uniqueidentifier = NULL OUTPUT) AS
BEGIN
IF @id IS NULL SET @id = NEWID()
-- INSERT INTO xyz (...) VALUES (@id, ...)
PRINT 'Insert with id: ' + CAST (@id as nvarchar(36))
END
GO
DECLARE @insertedId uniqueidentifier
EXECUTE test '00000000-0000-0000-0000-000000000000'
EXECUTE test @insertedId OUTPUT
PRINT @insertedId
DROP PROCEDURE test
打印出来
Insert with id: 00000000-0000-0000-0000-000000000000
Insert with id: 67AE3D27-8EAB-4301-B384-30EEA1488440
67AE3D27-8EAB-4301-B384-30EEA1488440
【讨论】:
【参考方案8】:另外两点我认为值得注意:
1) 你可以传递多个参数为OUTPUT
,
2) 如果您不想要结果,则不必使用OUTPUT
调用参数
CREATE PROCEDURE ManyOutputs @a int, @b int output, @c varchar(100) output, @d bit output
AS
BEGIN
SET @b = @a + 11
SET @c = 'The Value of A is ' + CAST(@a AS varchar(5)) + ', and the value of B is ' + CAST(@b AS varchar(5))
IF (@a % 2 = 1)
SET @d = 1
ELSE
SET @d = 0
END
GO
调用此例程:
DECLARE @bVal int
DECLARE @cVal varchar(100)
DECLARE @dVal bit
EXEC ManyOutputs 1, @bVal, @cVal, @dVal
SELECT @bVal AS bVal, @cVal as cVal, @dVal as dVal
返回 NULL、NULL、NULL
EXEC ManyOutputs 2, @bVal OUT, @cVal OUT, @dVal OUT
SELECT @bVal AS bVal, @cVal as cVal, @dVal as dVal
返回13,“A的值为2,B的值为13”,0
EXEC ManyOutputs 3, @bVal, @cVal, @dVal
SELECT @bVal AS bVal, @cVal as cVal, @dVal as dVal
返回13,“A的值为2,B的值为13”,0
(和上次调用一样,因为我们没有使用OUTPUT
获取新值,所以它保留了旧值。)
EXEC ManyOutputs 5, @bVal OUT, @cVal OUT, @dVal OUT
SELECT @bVal AS bVal, @cVal as cVal, @dVal as dVal
返回 16,“A 的值为 5,B 的值为 16”,1
【讨论】:
以上是关于SQL Server 输出参数问题的主要内容,如果未能解决你的问题,请参考以下文章
sql server 中 一个要输入参数和输出参数的存储过程。
什么可能导致 SQL Server JDBC 错误“未为参数号 0 设置值”以访问输出参数?
调用使用 Microsoft SQL Server 的输出参数的 Oracle 存储过程
SQL SERVER 存储过程执行带输出参数的SQL语句拼接