8

He configurado un Procedimiento almacenado en SQL Server que funciona bien. Ahora puedo llamarlo desde VBA, pero desea devolver un valor para saber si hubo algún error, etc. El último parámetro en mi SP está configurado como SALIDA:Cómo devolver valores de un SQL Server Stored Procedure y utilizarlos en Access VBA

@DataSetID int = 0, 
@Destination char(1)='-', 
@errStatusOK bit OUTPUT 

Mi VBA para llamar al SP está por debajo , pero no va a funcionar ahora, después de añadir el nuevo parámetro y no estoy seguro de dónde voy mal, me siguen dando 3708 - Parameter object is improperly defined. Inconsistent or incomplete information was provided.:

Set cnn = New adodb.Connection 
cnn.ConnectionString = 
    "DRIVER=SQL Server;SERVER=SERVER\SERVER;DATABASE=a_db;Trusted_Connection=Yes" 

cnn.Open cnn.ConnectionString 

Set cmd = New adodb.Command 
cmd.ActiveConnection = cnn 
cmd.CommandType = adCmdStoredProc 
cmd.CommandText = "stprMoveDataSet" 

Set param = cmd.CreateParameter 
       ("@DataSetID", adInteger, adParamInput, , stDataSet) 
cmd.Parameters.Append param 
Set param = cmd.CreateParameter 
       ("@Destination", adChar, adParamInput, 1, stDestination) 
cmd.Parameters.Append param 
Set param = cmd.CreateParameter 
       ("@errStatusOK", adBit, adParamReturnValue) 
cmd.Parameters.Append param 

rs.CursorType = adOpenStatic 
rs.CursorLocation = adUseClient 
rs.LockType = adLockOptimistic 
rs.Open cmd 

¿Cómo puedo obtener el VBA para trabajar con la salida parámetro y hacer que el valor de retorno sea 'legible' por la vba.

EDITAR - He cambiado la pregunta para que sea más específica sobre la devolución de valores y no solo sobre el uso de los parámetros OUTPUT.

Respuesta

7
Set cnn = New adodb.Connection 
cnn.ConnectionString = 
    "DRIVER=SQL Server;SERVER=SERVER\SERVER;DATABASE=a_db;Trusted_Connection=Yes" 

cnn.Open cnn.ConnectionString 

Set cmd = New adodb.Command 
cmd.ActiveConnection = cnn 
cmd.CommandType = adCmdStoredProc 
cmd.CommandText = "stprMoveDataSet" 

Set param1 = cmd.CreateParameter 
       ("@DataSetID", adInteger, adParamInput, , stDataSet) 
cmd.Parameters.Append param 
Set param2 = cmd.CreateParameter 
       ("@Destination", adChar, adParamInput, 1, stDestination) 
cmd.Parameters.Append param 
Set param3 = cmd.CreateParameter 
       ("@errStatusOK", adBit, adParamOutput, , adParamReturnValue) 
cmd.Parameters.Append param 

rs.CursorType = adOpenStatic 
rs.CursorLocation = adUseClient 
rs.LockType = adLockOptimistic 
rs.Open cmd 
+0

Debes haber publicado esto mientras estaba publicando mi propia respuesta, entiendo cómo me equivoqué con CreateParameter ahora. Muchas gracias, pueden usar eso en el futuro. – aSystemOverload

2

Entre otras enumeraciones de parámetros de las que se toma "adParamInput", otra es "adParamOutput", que es para indicar un parámetro de salida de un procedimiento almacenado, y "adParamInputOutput" para un parámetro que va "en ambas direcciones", como estaba. En su caso, creo que "adParamOutput" sería apropiado. Espero que esto sea lo que estás buscando.

+0

No es lo que estaba buscando, pero útil. Un colega sugirió que simplemente proporcione la salida a través de un SELECT @errStatusOK, etc. y que lo manipule en el VBA, lo que ha funcionado. Gracias – aSystemOverload

4

Me inicialmente miraba a los parámetros de salida, pero no pudo encontrar la manera de conseguir de nuevo a Access (VBA) a continuación, proporcionar información al usuario. Un colega sugirió usar un SELECCIONAR en el procedimiento Almacenado y usar esto.

procedimiento almacenado: ha añadido la siguiente al final:

SELECT @errStatusOK as errStatusOK, @countCurrent as countCurrent, @countHistorical as countHistorical 

VBA:

Dim cnn As ADODB.Connection 
Dim cmd As New ADODB.Command, rs As New ADODB.Recordset, param As New ADODB.Parameter 
Dim fld As ADODB.Field 
Dim stMessage As String 

Set cnn = New ADODB.Connection 
cnn.ConnectionString = "DRIVER=SQL Server;SERVER=SERVER\SERVER;DATABASE=a_db;Trusted_Connection=Yes" 

cnn.Open cnn.ConnectionString 

Set cmd = New ADODB.Command 
cmd.ActiveConnection = cnn 
cmd.CommandType = adCmdStoredProc 
cmd.CommandText = "stprMoveDataSet" 

Set param = cmd.CreateParameter("@DataSetID", adInteger, adParamInput, , stDataSet) 
cmd.Parameters.Append param 
Set param = cmd.CreateParameter("@Destination", adChar, adParamInput, 1, stDestination) 
cmd.Parameters.Append param 

rs.CursorType = adOpenStatic 
rs.CursorLocation = adUseClient 
rs.LockType = adLockOptimistic 
'rs.Open cmd 
Set rs = cmd.Execute 
If rs!errstatusok = True Then 
    stMessage = "Operation appears to have been successful, check the DataSets Listing..." & Chr(13) & "Also, the Server returned the following information: [" 
Else 
    stMessage = "Operation appears to have failed, check the DataSets Listing..." & Chr(13) & "Also, the Server returned the following information: [" 
End If 
For Each fld In rs.Fields 
    stMessage = stMessage & "| " & fld.Name & "/" & fld.Value & " |" 
Next fld 
stMessage = stMessage & "]" 

MsgBox stMessage 

Esto devuelve el folliwing: Operation appears to have failed, check the DataSets Listing... Also, the Server returned the following information: [| errStatusOK/False || countCurrent/0 || countHistorical/10 |]

+0

Sin duda, puede utilizar los parámetros de salida, así como el valor de retorno o los registros afectados. Ver mi respuesta –

4

Varias formas son posibles de obtener valores de nuevo usando VBA.

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

Mi código muestra los cuatro. Aquí hay 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á el sub que uso 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