2009-04-14 126 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