2009-04-14 22 views
32

Probablemente una pregunta fácil de responder. Tengo este procedimiento:Cómo obtener el valor devuelto de un procedimiento almacenado

CREATE PROCEDURE [dbo].[AccountExists] 
    @UserName nvarchar(16) 
AS 
IF EXISTS (SELECT Id FROM Account WHERE [email protected]) 
SELECT 1 
ELSE SELECT 0 

Cuando tengo código de ADO.NET que llama a este procedimiento y hace esto: se devuelve

return Convert.ToBoolean(sproc.ExecuteScalar()); 

verdadera o falsa.

Cuando cambio el procedimiento almacenado para RETURN 1 o 0 en lugar de 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() devuelve un valor nulo. Si pruebo sproc.ExecuteNonQuery() en su lugar, se devuelve -1.

¿Cómo obtengo el resultado de un procedimiento almacenado con un RETORNO en ADO.NET?

necesito AccountExists a RETURN en lugar de SELECT para que pueda tener otro procedimiento almacenado llamarlo:

--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: El tema debe editarse para ser más específico. Desde el tema, la pregunta podría ser cualquier cosa que ver con T-SQL y ADO.NET. –

+0

lol, eso fue involuntario. Mi atención debe haber sido desviada mientras escribo el tema. – core

Respuesta

40

añadir un parámetro, utilizando ParameterDirection.ReturnValue. El valor de retorno estará presente en el parámetro después de la ejecución.

+3

Esto no me funcionaba en VBA hasta que descubrí que ReturnValue debe ser el primer parámetro. http://stackoverflow.com/a/25528645/2559297 –

+0

"Agregar un parámetro al comando" ¿Al procedimiento almacenado? – TylerH

0

Si está planeando usarlo como en el ejemplo a continuación, AccountExists podría estar mejor como una función.

De lo contrario, todavía debería poder obtener el resultado del procedimiento almacenado llamándolo desde otro seleccionando el resultado.

3

ExecuteScalar devuelve la primera columna de la primera fila. Como ya no seleccionaba más y creaba un conjunto de resultados, es por eso que devolvía nulo. Justo como FYI. John Saunders tiene la respuesta correcta.

1

Solo algunos consejos, pero de forma predeterminada, un procedimiento almacenado devuelve 0 a menos que especifique algo más. Por esta razón, 0 se usa a menudo para designar el éxito y los valores distintos de cero se usan para especificar condiciones de error de retorno. Me gustaría ir con John's suggestion, o utilizar un output parameter

9

Además, para recuperar el resultado (o cualquier otro parámetro de salida para el caso) de ADO.NET que tiene que recorrer todos los conjuntos de resultados devueltos primero (o saltar con NextResult)

esto significa que si usted tiene un procedimiento definido así:

CREATE PROC Test(@x INT OUT) AS 
    SELECT * From TestTable 
    SELECT @x = 1 

y tratar de hacer esto:

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; 

Entonces x contendrá nulo. Para que funcione, debe ejecutar el procedimiento como:

using (var rdr = cmd.ExecuteReader()) { 
    while (rdr.Read()) 
     MaybeDoSomething; 
} 
int? x = cmd.Parameters["@x"].Value is DBNull ? null : (int?)cmd.Parameters["@x"].Value; 

En este último caso, x contendrá 1 como se esperaba.

+0

@erikkallen: es posible que desee aclarar que quiere decir que es necesario recorrer todos los conjuntos de resultados que implican llamadas a procedimientos almacenados con parámetros de salida o valor de retorno. –

2

Probé las otras soluciones con mi configuración y no funcionaron, pero estoy usando VB6 & ADO 6.x. También quiero señalar que un retorno de proceso de 0 indica éxito. No olvide que hay funciones disponibles que no tienen esa convención.Encontramos este en MSDN y lo hizo el trabajo para mí:

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) 

Los resultados aparecen en la ventana inmediata cuando se ejecuta este (Debug.Print)

0

Varias formas son posibles de obtener valores de nuevo utilizando VBA:

  1. de registros
  2. Conde de registros afectados (sólo para Insertar/Actualizar/Eliminar de otro modo -1)
  3. parámetro de salida
  4. Valor de retorno

Mi código muestra los cuatro. Aquí es un procedimiento almacenado que devuelve un valor:

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 

Aquí está la sub utilizo en Excel VBA. Necesitará referencia a la biblioteca 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 
Cuestiones relacionadas