2009-04-14 127 views
32

可能是一个易于回答的问题。我有这样的过程:如何获得存储过程的返回值

CREATE PROCEDURE [dbo].[AccountExists] 
    @UserName nvarchar(16) 
AS 
IF EXISTS (SELECT Id FROM Account WHERE [email protected]) 
SELECT 1 
ELSE SELECT 0 

当我有一个调用这个过程,这是否ADO.NET代码:返回

return Convert.ToBoolean(sproc.ExecuteScalar()); 

无论是真的还是假的。

当我更改存储的过程返回1或0,而不是SELECT的:

ALTER PROCEDURE [dbo].[AccountExists] 
    @UserName nvarchar(16) 
AS 
IF EXISTS (SELECT Id FROM Account WHERE [email protected]) 
RETURN 1 
ELSE RETURN 0 

sproc.ExecuteScalar()返回null。如果我尝试使用sproc.ExecuteNonQuery(),则返回-1。

如何在ADO.NET中使用RETURN获取存储过程的结果?

我需要AccountExists反送回来SELECT的,所以我可以有另一个存储过程调用它:

--another procedure to insert or update account 

DECLARE @exists bit 

EXEC @exists = [dbo].[AccountExists] @UserName 

IF @exists=1 
--update account 
ELSE 
--insert acocunt 
+0

@Chris:主题应该被编辑为更具体。从主题来看,这个问题可能与T-SQL和ADO.NET有关。 – 2009-04-14 22:46:31

+0

大声笑,这是无意的。当我输入主题时,我的注意力一定被转移了。 – core 2009-04-14 22:58:09

回答

40

添加参数,使用ParameterDirection.ReturnValue。执行后返回值将出现在参数中。

+3

直到我发现ReturnValue必须是第一个参数之前,这在VBA中不适用于我。 http://stackoverflow.com/a/25528645/2559297 – 2015-07-31 07:58:54

0

如果您打算像下面的例子那样使用它,AccountExists可能会更好。

否则,您应该仍然能够通过对结果进行选择来从另一个对象调用存储过程的结果。

3

ExecuteScalar返回第一行的第一列。由于您不再选择和创建结果集,这就是它返回null的原因。就像FYI一样。约翰桑德斯有正确的答案。

1

只是一些建议,但默认情况下,存储过程将返回0,除非您指定了其他内容。出于这个原因,0通常用于指定成功,而非零值用于指定返回错误条件。我想用John's suggestionoutput parameter

9

此外,要从ADO.NET中检索结果(或任何其他输出参数),必须首先遍历所有返回的结果集(或使用NextResult跳过它们)

这意味着,如果你有一个像这样定义的过程:

CREATE PROC Test(@x INT OUT) AS 
    SELECT * From TestTable 
    SELECT @x = 1 

并尝试做到这一点:

SqlCommand cmd = connection.CreateCommand(); 
cmd.CommandType = CommandType.StoredProcedure; 
cmd.CommandText = "Test" 
cmd.Parameters.Add("@x", SqlDbType.Int).Direction = ParameterDirection.Output; 
cmd.Parameters.Add("@retval", SqlDbType.Int).Direction = ParameterDirection.ReturnValue; 

cmd.Execute(); 
int? x = cmd.Parameters["@x"].Value is DBNull ? null : (int?)cmd.Parameters["@x"].Value; 

然后x将包含null。要使其工作,您必须执行如下程序:

using (var rdr = cmd.ExecuteReader()) { 
    while (rdr.Read()) 
     MaybeDoSomething; 
} 
int? x = cmd.Parameters["@x"].Value is DBNull ? null : (int?)cmd.Parameters["@x"].Value; 

在后一种情况下,x将按预期包含1。

2

我试着用我的设置其他解决方案,他们没有工作,但我使用VB6 & ADO 6.x.我也想指出一个0的返回值表示成功。不要忘记也有可用的功能,这些功能没有这个约定。 发现这个MSDN上,它为我做的工作:运行此(Debug.Print)时

Debug.Print "starting at ..." & TimeValue(Now) 

Dim cn As New ADODB.Connection 
Dim cmd As New ADODB.Command 
'These are two possible connection strings. You could also have Integrated Security instead of these for SqS for security 
'cn.ConnectionString = "Data Source=[yourserver];User ID=[youruser];Password=[yourpw];Initial Catalog=[yourdb];Provider=SQLNCLI10.1;Application Name=[yourapp]" 
cn.ConnectionString = "Data Source=[yours];User ID=[youruser];Password=[yourpassword];Initial Catalog=[Yourdb];Provider=sqloledb;Application Name=[yourapp]" 
cn.Open 

cmd.ActiveConnection = cn 
cmd.CommandText = "AccountExists" 
cmd.CommandType = adCmdStoredProc 
cmd.Parameters.Append cmd.CreateParameter(, adInteger, adParamReturnValue) 
cmd.Parameters.Append cmd.CreateParameter("UserName",adVarChar, adParamInput, 16, UserNameInVB) 

cmd.Execute 
Debug.Print "Returnval: " & cmd.Parameters(0) 
cn.Close 

Set cmd = Nothing 
Set cn = Nothing 

Debug.Print "finished at ..." & TimeValue(Now) 

结果将出现在即时窗口

0

几种方法都可以回去使用VBA值:

  1. 记录
  2. 记录计数的影响(仅适用于插入/更新/删除,否则-1)
  3. 输出参数
  4. 返回值

我的代码演示了所有四个。这里是一个返回值的存储过程:

Create PROCEDURE CheckExpedite 
    @InputX varchar(10), 
    @InputY int, 
    @HasExpedite int out 
AS 
BEGIN 
    Select @HasExpedite = 9 from <Table> 
    where Column2 = @InputX and Column3 = @InputY 

    If @HasExpedite = 9 
     Return 2 
    Else 
     Return 3 
End 

下面是我在Excel VBA中使用子。您需要参考Microsoft ActiveX Data Objects 2.8 Library。

Sub CheckValue() 

    Dim InputX As String: InputX = "6000" 
    Dim InputY As Integer: InputY = 2014 

    'open connnection 
    Dim ACon As New Connection 
    ACon.Open ("Provider=SQLOLEDB;Data Source=<SqlServer>;" & _ 
     "Initial Catalog=<Table>;Integrated Security=SSPI") 

    'set command 
    Dim ACmd As New Command 
    Set ACmd.ActiveConnection = ACon 
    ACmd.CommandText = "CheckExpedite" 
    ACmd.CommandType = adCmdStoredProc 

    'Return value must be first parameter else you'll get error from too many parameters 
    'Procedure or function "Name" has too many arguments specified. 
    ACmd.Parameters.Append ACmd.CreateParameter("ReturnValue", adInteger, adParamReturnValue) 
    ACmd.Parameters.Append ACmd.CreateParameter("InputX", adVarChar, adParamInput, 10, InputX) 
    ACmd.Parameters.Append ACmd.CreateParameter("InputY", adInteger, adParamInput, 6, InputY) 
    ACmd.Parameters.Append ACmd.CreateParameter("HasExpedite", adInteger, adParamOutput) 

    Dim RS As Recordset 
    Dim RecordsAffected As Long 

    'execute query that returns value 
    Call ACmd.Execute(RecordsAffected:=RecordsAffected, Options:=adExecuteNoRecords) 

    'execute query that returns recordset 
    'Set RS = ACmd.Execute(RecordsAffected:=RecordsAffected) 

    'get records affected, return value and output parameter 
    Debug.Print "Records affected: " & RecordsAffected 
    Debug.Print "Return value: " & ACmd.Parameters("ReturnValue") 
    Debug.Print "Output param: " & ACmd.Parameters("HasExpedite") 

    'use record set here 
    '... 

    'close 
    If Not RS Is Nothing Then RS.Close 
    ACon.Close 

End Sub