Probablement une question facile à répondre. J'ai cette procédure:
CREATE PROCEDURE [dbo].[AccountExists]
@UserName nvarchar(16)
AS
IF EXISTS (SELECT Id FROM Account WHERE UserName=@UserName)
SELECT 1
ELSE SELECT 0
Lorsque j'ai du code ADO.NET qui appelle cette procédure et le fait:
return Convert.ToBoolean(sproc.ExecuteScalar());
Vrai ou faux est retourné.
Lorsque je change la procédure stockée en RETOUR 1 ou 0 au lieu de 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 () renvoie null. Si j'essaie à la place sproc.ExecuteNonQuery (), -1 est renvoyé.
Comment obtenir le résultat d'une procédure stockée avec un RETOUR dans ADO.NET?
J'ai besoin de AccountExists pour RETOUR au lieu de SELECT afin que je puisse avoir une autre procédure stockée l'appeler:
--another procedure to insert or update account
DECLARE @exists bit
EXEC @exists = [dbo].[AccountExists] @UserName
IF @exists=1
--update account
ELSE
--insert acocunt
Ajoutez un paramètre en utilisant ParameterDirection.ReturnValue
. La valeur de retour sera présente dans le paramètre après l'exécution.
De plus, pour récupérer le résultat (ou tout autre paramètre de sortie d'ailleurs) d'ADO.NET, vous devez d'abord parcourir tous les jeux de résultats retournés (ou les ignorer avec NextResult)
Cela signifie que si vous avez une procédure définie comme ceci:
CREATE PROC Test(@x INT OUT) AS
SELECT * From TestTable
SELECT @x = 1
Et essayez de faire ceci:
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;
Alors x contiendra null. Pour le faire fonctionner, vous devez exécuter la procédure comme:
using (var rdr = cmd.ExecuteReader()) {
while (rdr.Read())
MaybeDoSomething;
}
int? x = cmd.Parameters["@x"].Value is DBNull ? null : (int?)cmd.Parameters["@x"].Value;
Dans ce dernier cas, x contiendra 1 comme prévu.
ExecuteScalar renvoie la première colonne de la première ligne. Étant donné que vous ne sélectionniez plus et ne créiez pas de jeu de résultats, c'est pourquoi il renvoyait null. Tout comme FYI. John Saunders a la bonne réponse.
J'ai essayé les autres solutions avec ma configuration et elles n'ont pas fonctionné mais j'utilise VB6 & ADO 6.x. Je tiens également à souligner qu'un retour de proc de 0 indique un succès. Don N'oubliez pas qu'il existe également des fonctions qui n'ont pas cette convention. J'ai trouvé cela sur MSDN et cela a fonctionné pour moi:
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)
Les résultats apparaîtront dans la fenêtre immédiate lors de l'exécution de ceci (Debug.Print)
Plusieurs méthodes sont possibles pour récupérer des valeurs à l'aide de VBA:
Mon code illustre les quatre. Voici une procédure stockée qui renvoie une valeur:
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
Voici le sous que j'utilise dans Excel VBA. Vous aurez besoin d'une référence à la bibliothèque Microsoft ActiveX Data Objects 2.8.
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
Juste quelques conseils, mais par défaut, une procédure stockée renvoie 0, sauf si vous spécifiez autre chose. Pour cette raison, 0 est souvent utilisé pour désigner le succès et des valeurs non nulles sont utilisées pour spécifier les conditions d'erreur de retour. J'irais avec suggestion de John , ou utiliser un output parameter
Si vous prévoyez de l'utiliser comme l'exemple ci-dessous, AccountExists pourrait être mieux en tant que fonction.
Sinon, vous devriez toujours pouvoir obtenir le résultat de la procédure stockée en l'appelant à partir d'une autre en effectuant une sélection sur le résultat.