簡體   English   中英

如何獲取存儲過程的返回值

[英]How to get Return Value of a Stored Procedure

可能是一個容易回答的問題。 我有這個程序:

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

使用ParameterDirection.ReturnValue添加ParameterDirection.ReturnValue 執行后,返回值將出現在參數中。

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

ExecuteScalar返回第一行的第一列。 由於您不再選擇並創建結果集,因此它返回null。 就像FYI一樣。 約翰桑德斯有正確的答案。

我用我的設置嘗試了其他解決方案但它們沒有用,但我使用的是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)

有幾種方法可以使用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

只是一些建議,但默認情況下,除非您指定其他內容,否則存儲過程將返回0。 因此,0通常用於指定成功,非零值用於指定返回錯誤條件。 我會考慮約翰的建議 ,或使用output parameter

如果您正在計划使用它,如下面的示例,AccountExists可能會更好地作為一個功能。

否則,您仍然可以通過對結果進行選擇來從另一個調用存儲過程的結果來獲取存儲過程的結果。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM