web-dev-qa-db-fra.com

Comment obtenir la valeur de retour d'une procédure stockée

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
33
core

Ajoutez un paramètre en utilisant ParameterDirection.ReturnValue. La valeur de retour sera présente dans le paramètre après l'exécution.

43
John Saunders

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.

10
erikkallen

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.

3
Darren Kopp

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)

2
Pecos Bill

Plusieurs méthodes sont possibles pour récupérer des valeurs à l'aide de VBA:

  1. Recordset
  2. Nombre d'enregistrements affectés (uniquement pour Insert/Update/Delete sinon -1)
  3. Paramètre de sortie
  4. Valeur de retour

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
1
D_Bester

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

1
Russ Cam

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.

0
Luke Lowrey