SQL Server输出参数问题

时间:2009-08-08 07:25:10

标签: sql sql-server sql-server-2008 stored-procedures

我正在使用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值(使其看起来像纯输出参数行为)?

8 个答案:

答案 0 :(得分:60)

混淆在某种程度上是合理的 - 而像Oracle这样的其他RDBMS确实有存储过程参数,可以是IN类型(仅输入),OUT(仅输出)或{{1 (两种方式 - “按引用传递”类型的参数)。

SQL Server在这里有点草率,因为它将参数标记为INOUT,但实际上,这意味着OUTPUT / INPUT - 它基本上只意味着存储过程有机会从该参数中调用返回值。

是的 - 即使它被称为OUTPUT参数,它实际上更像是OUTPUT / INPUT参数,而OUTPUTIN,{ {1}}在SQL Server中不存在(在T-SQL中)。

答案 1 :(得分:19)

我可以举例说明如何使用输出参数创建存储过程。

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

你知道,你应该首先声明ouput变量。执行存储过程后,输出值将在您的变量中。您可以为输出变量设置任何值,但在执行存储过程后,它将包含确切的存储过程返回值(无论输出变量中的值是什么)。

例如:

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.

答案 2 :(得分:6)

是的,您可以使用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

编辑:好的,我想我错过了第二段中的“不”,可能没有回答你提出的问题。如果你想要一个严格的输出参数(例如返回代码之类的东西),你当然不必为作为输出参数传递的局部变量提供,但你仍然必须声明局部变量,以便您可以在过程本身范围之外访问返回值。

例如:

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

答案 3 :(得分:3)

进一步增加其他人的说法,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参数的值(不使用输出参数)。

e.g。我不能在c#中这样做。这里它只作为out参数(即忽略传递给该函数的用户值)

static void dosomething(out int i)
{
    //i = 0;
    i = i + 1;
}

答案 4 :(得分:2)

问题是 - 为什么你想不允许提供输入?这没有任何意义。考虑这个简单的例子:

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

请参阅 - 如果您未首先在中添加变量,那么您应该如何获得值

答案 5 :(得分:2)

考虑在编程语言中通过引用传递的OUTPUT PARAMETERS,它是相同的。我现在能想到的最好的例子是返回错误代码。你想要一些插入...如果从SP中选择返回代码,你必须在代码中取回它,使用你没有的OUTPUT参数,它将在你的参数中(我的意思是使用C#命令,PHP init存储过程方法,或者不同的东西,然后构造字符串)

答案 6 :(得分:2)

关于原始问题的一部分的另外一个注释:

  

“是否允许不为OUTPUT参数(..)提供任何INPUT值?”

在SQLServer中,可以为OUTPUT参数指定默认值(正如其他人实际指出的那样)。请考虑以下示例,您可以在其中指定显式值或让函数本身生成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

答案 7 :(得分:0)

我认为还有两点值得注意:

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