如何获取存储过程的返回值

时间:2009-04-14 22:39:37

标签: sql tsql stored-procedures ado.net

可能是一个容易回答的问题。我有这个程序:

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

当我有调用此过程的ADO.NET代码并执行此操作时:

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

返回true或false。

当我将存储过程更改为RETURN 1或0而不是SELECT:

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

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

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

我需要AccountExists来RETURN而不是SELECT,所以我可以让另一个存储过程调用它:

--another procedure to insert or update account

DECLARE @exists bit

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

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

7 个答案:

答案 0 :(得分:42)

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

答案 1 :(得分:10)

此外,要从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 :(得分:3)

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

答案 3 :(得分:2)

我用我的设置尝试了其他解决方案但它们没有用,但我使用的是VB6& ADO 6.x.我还想指出proc返回0表示成功。不要忘记有些功能也没有那种惯例。 在MSDN上找到它,它确实对我有用:

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)

运行此结果(Debug.Print)时,结果将显示在即时窗口中

答案 4 :(得分:1)

只是一些建议,但默认情况下,除非您指定其他内容,否则存储过程将返回0。因此,0通常用于指定成功,非零值用于指定返回错误条件。我会选择John's suggestion,或使用output parameter

答案 5 :(得分:1)

有几种方法可以使用VBA获取值:

  1. 记录
  2. 受影响的记录数(仅适用于插入/更新/删除,否则为-1)
  3. 输出参数
  4. 返回值
  5. 我的代码演示了所有四个。这是一个返回值的存储过程:

    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
    

答案 6 :(得分:0)

如果你正在计划使用它,就像下面的例子一样,AccountExists作为一个功能可能会更好。

否则,您仍然可以通过对结果进行选择来从另一个调用存储过程的结果来获取存储过程的结果。