【问题标题】:How to get Return Value of a Stored Procedure如何获取存储过程的返回值
【发布时间】:2010-10-19 11:24:40
【问题描述】:

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

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());

返回真或假。

当我将存储过程更改为 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 来返回而不是 SELECT,这样我就可以让另一个存储过程调用它:

--another procedure to insert or update account

DECLARE @exists bit

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

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

【问题讨论】:

  • @Chris:主题应该被编辑得更具体。从这个主题来看,这个问题可能与 T-SQL 和 ADO.NET 有关。
  • 大声笑,那是无意的。当我输入主题时,我的注意力一定被转移了。

标签: sql tsql stored-procedures ado.net


【解决方案1】:

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

【讨论】:

【解决方案2】:

如果您打算像下面的示例那样使用它,AccountExists 作为一个函数可能会更好。

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

【讨论】:

    【解决方案3】:

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

    【讨论】:

      【解决方案4】:

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

      【讨论】:

        【解决方案5】:

        此外,要从 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。

        【讨论】:

        • @erikkallen:您可能想澄清一下,您的意思是有必要遍历所有涉及使用输出或返回值参数调用存储过程的结果集。
        【解决方案6】:

        我用我的设置尝试了其他解决方案,但它们不起作用,但我使用的是 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)时,结果将出现在即时窗口中

        【讨论】:

          【解决方案7】:

          有几种方法可以使用 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
          

          【讨论】:

            猜你喜欢
            • 2010-12-12
            • 1970-01-01
            • 1970-01-01
            • 2019-01-04
            • 1970-01-01
            • 1970-01-01
            • 2013-01-22
            • 1970-01-01
            相关资源
            最近更新 更多