ADODB.Command.Execute not working with parameter - vba

I'm trying to create a function in VBA to handle my SQL procedure calls. I've run into a problem where if the code needs to supply a parameter to the procedure it is not working. The code is below, it works fine if I call the procedure without the optional argument. I've added a breakpoint before the execute; the if statement triggers fine and the immediate window tells me that ?cmd.Parameters(0) and ?cmd.Parameters(1) have values yet I get the error: myprocedure expects parameter '#sd_name' which was not supplied. The procedure only expects 2 arguments and I don't even care about the name, they can just be passed by position.
Function RunSQL(comtext As String, Optional Params As String = "No") As ADODB.Recordset
Dim cmd As New ADODB.Command
Dim recset As New ADODB.Recordset
Dim prm As ADODB.Parameter
TryConnect
cmd.commandtext = comtext
cmd.CommandType = adCmdText
cmd.ActiveConnection = GlobalCon
cmd.CommandTimeout = 0
If Params <> "No" Then
Set prm = cmd.CreateParameter("#sd_name", adVarChar, adParamInput, 100)
cmd.Parameters.Append prm
cmd.Parameters("#sd_name").Value = Params
Set prm = cmd.CreateParameter("#year_wk_num", adInteger, adParamInput, 100)
cmd.Parameters.Append prm
cmd.Parameters("#year_wk_num").Value = ThisWorkbook.Sheets("Control Sheet").Range("year_wk").Value
End If
--------------!Error Here----------------
Set recset = cmd.Execute
Set RunSQL = recset
Set cmd = Nothing
End Function

Got it, simple mistake, seems you cannot add parameters in this way to ADODB.Command.CommandType adCmdText rather it must be adCmdStoredProc. I guess you can probably add them as part of the commandtext string if you wish to use that type as msdn is saying it can be used as a textual definition of a stored procedure. However in this case I've just done the below and it's working fine (Still needs to be adCmdText when no parameters are required and calling VBA defined query string rather than procedure):
If Params <> "No" Then
cmd.CommandType = adCmdStoredProc 'added this line

Related

SQL SP not returning a value to ADO execute

OK, I'm missing something obvious here - I have an SP that takes in an integer ID and returns a string. I've used this SP for quite a while with DAO. Now I need to switch to ADO so I can run it under and existing connection (another question I'll post elsewhere).
So my code follows. It returns no errors but it also returns no results. The output parameter is null. What am I missing?
Dim adoCon As ADODB.Connection
Dim adoCMD As ADODB.Command
Dim SQLstr As String
Dim ConStr As String
'--- get connection string from existing object, but strip leading odbc; piece
ConStr = Replace(CurrentDb.TableDefs("[TableName]").Connect, "ODBC;", "")
Set adoCon = New ADODB.Connection
adoCon.ConnectionString = ConStr
adoCon.Open
Set adoCMD = New ADODB.Command
With adoCMD
.ActiveConnection = adoCon
.CommandType = adCmdStoredProc
.Parameters.Append .CreateParameter(, adInteger, adParamReturnValue, , Null) ' return value
.Parameters.Append .CreateParameter("Path", adVarChar, adParamOutput, 500, Null)
.Parameters.Append .CreateParameter("AsyID", adInteger, adParamInput)
.Parameters.Item("AsyID").Value = AsyID
.CommandText = "dbo.spGetAncestry"
.Execute
End With
GetHeritage = adoCMD.Parameters(1).Value 'parm(0) = 0; parm(1) = NULL; parm(2) = AsyID
adoCon.Close
Although your code should work. Please remove the optional expressions in the parameter definition and try the following:
Dim rv as Integer
Set adoCMD = New ADODB.Command
With adoCMD
.ActiveConnection = adoCon
.CommandType = adCmdStoredProc
.Parameters.Append .CreateParameter("RETURN_VALUE", adInteger, adParamReturnValue)
.Parameters.Append .CreateParameter("Path", adVarChar, adParamOutput, 500)
.Parameters.Append .CreateParameter("AsyID", adInteger, adParamInput, , AsyID)
.CommandText = "dbo.spGetAncestry"
.Execute
End With
rv = adoCMD.Parameters("RETURN_VALUE").Value
GetHeritage = adoCMD.Parameters("Path").Value
also make sure your SP is returning the correct data type and size for your output parameter and adjust the code accordingly. If you're returning VARCHAR(MAX), then that is treated as a "BLOB" in ADO, see this related question What are the limits for ADO data types?.
In this case you can try returning varchar(8000) from the SP and updating the code accordingly.
Found it.
Apparently, in the ADO call, it doesn't matter what you set the return value to (I was trying to use "" or even " " before I set it to null) when it executes in SQL batch, it is simply set to NULL as it shows in this trace form. For this run, the Output was initialized as " ", but the batch passed in NULL.
[!SQL trace of the above query being executed with " " in the initialization of the Output variable1]1
Normally, a null wouldn't be a problem as the typical SP assignment would be:
SET #Path = [SELECT value from table]
or, if it was a concatenation, you would initialize the variable:
SET #Path = ''
before stringing together the input.
In this particular case, though, the SP is recursive. It calls itself passing an input and the output values to the new copy. Because of this, you can't initialize the value and you can't use a straight assignment. To get around this, I needed to use:
#path = COALESCE(#path, '') + [SELECT value from table]
to trap any NULL passed in.

Calling a SQL server procedure from a function in VBA

I am trying to call a SQL Server procedure to validate user from a function in VBA.
Please see the code below:
proc_validate_user accepts userId and password as input parameters and returns a bit value of 0 or 1
function to call this proc is as under:
Public Function ExecUDF(userId As Integer, pwd As String)
Dim cmd As DAO.Command
Dim par As DAO.Parameter
Dim ret As Variant
Set cmd = New DAO.Command
cmd.ActiveConnection = CurrentDb.Connection
cmd.CommandText = "proc_validate_user"
cmd.CommandType = adCmdStoredProc
'Define the input and output variables and append them to the collection
Set par = cmd.CreateParameter("#userID")
cmd.Parameters.Append par
Set par = cmd.CreateParameter("#pwd")
cmd.Parameters.Append par
Set par = cmd.CreateParameter("#isValid", adParamOutput)
cmd.Parameters.Append par
cmd.Parameters("#userID") = userId
cmd.Parameters("#pwd") = pwd
cmd.Execute
'and then assign the stored procedure return value to the access variable
ret = cmd.Parameters("#isValid").Value
End Function
I am getting an compilation error saying User defined type not defined at "Dim cmd As DAO.Command"
You are mixing up the DAO and ADO object models. DAO is a completely different model, not a "subset of ADO". There is no DAO.Command object.
SQL Server stored procedures that produce output parameters can be a nuisance to work with using DAO. The ADO model is much better aligned with SQL Server, so I would suggest using code like this:
Public Function ExecUDF(userId As Integer, pwd As String) As Boolean
Dim con As ADODB.Connection, cmd As ADODB.Command, connStr As String, isValid As Boolean
' remove "ODBC;" prefix from the .Connect property of an existing ODBC linked table
connStr = Mid(CurrentDb.TableDefs("dbo_my_table").Connect, 6)
Set con = New ADODB.Connection
con.Open connStr
Set cmd = New ADODB.Command
cmd.ActiveConnection = con
cmd.CommandType = adCmdStoredProc
cmd.CommandText = "proc_validate_user"
cmd.Parameters.Append cmd.CreateParameter("#userID", adInteger, adParamInput, , userId)
cmd.Parameters.Append cmd.CreateParameter("#pwd", adVarWChar, adParamInput, 50, pwd)
cmd.Parameters.Append cmd.CreateParameter("#isValid", adBoolean, adParamOutput)
cmd.Execute
isValid = cmd.Parameters("#isValid").Value
Set cmd = Nothing
con.Close
Set con = Nothing
ExecUDF = isValid ' return the value
End Function

Error trying to call stored procedure with prepared statement

I'm trying to use a prepared statement to call a stored procedure (using ADODB with classic ASP), but when I set CommandType I get the following error:
ADODB.Command error '800a0bb9'
Arguments are of the wrong type, are out of acceptable range, or are in conflict with one another.
I have the following code:
With Server.CreateObject("ADODB.Command")
.ActiveConnection = db 'this is initialized prior
.CommandType = adCmdStoredProc
.CommandText = "procName"
End With
The prepared statement name is correct (I'm able to call it just by executing the string), and if I leave out the .CommandType and try calling .Execute, I get an error specifying:
Procedure or function 'procName' expects parameter '#ParamName', which was not supplied.
Even if I leave out the CommandType, I have no idea how to actually add the parameter (something along the following lines just results in the original error about arguments of the wrong type):
.Parameters.Append .CreateParameter("#ParamName",adVarChar,adParamInput,50,param)
I've also tried the following and got an error "Item cannot be found in the collection corresponding to the requested name or ordinal."
.Parameters.Refresh
.Parameters(0) = param
I've looked at several examples of how to call stored procedures using prepared statements, and it looks like I'm using the right syntax, but anything I try seems to result in some kind of error. Any help would be greatly appreciated.
You want something like this (untested)
Dim cmd, rs, ars, conn
Set cmd = Server.CreateObject("ADODB.Command")
With cmd
'Assuming passing connection string if passing ADODB.Connection object
'make sure you use Set .ActiveConnection = conn also conn.Open should
'have been already called.
.ActiveConnection = conn
'adCmdStoredProc is Constant value for 4 (include adovbs or
'set typelib in global.asa)
.CommandType = adCmdStoredProc
.CommandText = "dbo.procName"
'Define parameters in ordinal order to avoid errors
Call .Parameters.Append(.CreateParameter("#ParamName", adVarChar, adParamInput, 50))
'Set values using parameter friendly name
.Parameters("#ParamName").Value = param
'Are you returning a recordset?
Set rs = .Execute()
'Populate array with data from recordset
If Not rs.EOF Then ars = rs.GetRows()
Call rs.Close()
Set rs = Nothing
End With
Set cmd = Nothing
It is important to remember that the friendly name (as I rule I tend to match my parameter names in my stored procedure to my friendly names in ADO) you give your parameter means nothing to the stored procedure as ADO passes the parameters ordinally and nothing more, the fact you get the error;
Procedure or function 'procName' expects parameter '#ParamName', which was not supplied.
Suggests that the stored procedure is expecting your #ParamName parameter (defined in your stored procedure) value to be passed from ADO in a different ordinal position, which usually means you have not defined all your parameters or passed all the parameter values in the position they are expected.
You can also do a shortened version if your confident of your ordinal positioning and parameter requirements
With cmd
.ActiveConnection = conn
.CommandType = adCmdStoredProc
.CommandText = "dbo.procName"
'Pass parameters as array following ordinal position.
Set rs = .Execute(, Array(param))
'Populate array with data from recordset
If Not rs.EOF Then ars = rs.GetRows()
Call rs.Close()
Set rs = Nothing
End With
Set cmd = Nothing
Working with a 2-dimensional array is easy and negates the overhead of working directly with a ADODB.Recordset.
Dim row, rows
If IsArray(ars) Then
rows = UBound(ars, 2)
For row = 0 To rows
Response.Write "First column from row " & row & " = " & ars(0, row) & "<br />"
Next
Else
Response.Write "No data to return"
End If
Links
Using METADATA to Import DLL Constants - If your having trouble with the ADO constants (adCmdStoredProc etc.) this will fix it for you.
Here is how you call a stored procedure in ASP classic:
'Set the connection
'...............
'Set the command
DIM cmd
SET cmd = Server.CreateObject("ADODB.Command")
SET cmd.ActiveConnection = Connection
'Set the record set
DIM RS
SET RS = Server.CreateObject("ADODB.recordset")
'Prepare the stored procedure
cmd.CommandText = "procName"
cmd.CommandType = 4 'adCmdStoredProc
'Assign value to the parameter
cmd.Parameters("#ParamName ") = ParamValue
'Execute the stored procedure
RS = cmd.Execute
SET cmd = Nothing
'You can now access the record set
if (not RS.EOF) THEN
data = RS("column_name")
end if
'dispose your objects
RS.Close
SET RS = Nothing
Connection.Close
SET Connection = Nothing

VBA, ADO.Connection and query parameters

I have excel VBA script:
Set cоnn = CreateObject("ADODB.Connection")
conn.Open "report"
Set rs = conn.Execute("select * from table" )
Script work fine, but i want to add parameter to it. For example " where (parentid = myparam)", where myparam setted outside query string. How can i do it?
Of course i can modify query string, but i think it not very wise.
You need to use an ADODB.Command object that you can add parameters to. Here's basically what that looks like
Sub adotest()
Dim Cn As ADODB.Connection
Dim Cm As ADODB.Command
Dim Pm As ADODB.Parameter
Dim Rs as ADODB.Recordset
Set Cn = New ADODB.Connection
Cn.Open "mystring"
Set Cm = New ADODB.Command
With Cm
.ActiveConnection = Cn
.CommandText = "SELECT * FROM table WHERE parentid=?;"
.CommandType = adCmdText
Set Pm = .CreateParameter("parentid", adNumeric, adParamInput)
Pm.Value = 1
.Parameters.Append Pm
Set Rs = .Execute
End With
End Sub
The question mark in the CommandText is the placeholder for the parameter. I believe, but I'm not positive, that the order you Append parameters must match the order of the questions marks (when you have more than one). Don't be fooled that the parameter is named "parentid" because I don't think ADO cares about the name other than for identification.
Alternative example returning a command from a function:
Function BuildCommand(conn As ADODB.Connection) As ADODB.Command
Dim cmd As ADODB.Command
Set cmd = New ADODB.Command
cmd.ActiveConnection = conn
cmd.CommandType = adCmdText
cmd.Parameters.Append cmd.CreateParameter("#name", adVarChar, adParamInput, 255, "Dave")
cmd.CommandText = "SELECT * FROM users WHERE name = #name;"
Set BuildCommand = cmd
End Function
A couple things to note:
When using adVarChar data type, the size argument to cmd.CreateParameter (e.g. 255) is required. Not supplying it results a run-time error 3708: Application-defined or object-defined error, as indicated in the documentation:
If you specify a variable-length data type in the Type argument, you must either pass a Size argument or set the Size property of the Parameter object before appending it to the Parameters collection; otherwise, an error occurs.
If the cmd.ActiveConnection property is set when cmd.CommandText is set, and cmd.CommandText contains named parameters, cmd.Parameters will be populated accordingly. Calling cmd.Parameters.Append afterwards could result in duplicates. For example:
cmd.ActiveConnection = conn
cmd.CommandType = adCmdText
Debug.Print cmd.Parameters.Count ' 0
cmd.CommandText = "SELECT * FROM users WHERE name = #name;"
Debug.Print cmd.Parameters.Count ' 1
cmd.Parameters.Append cmd.CreateParameter("#name", adVarChar, adParamInput, 255, "Dave")
Debug.Print cmd.Parameters.Count ' 2
I believe this is what is meant in the documentation, which is slightly inaccurate:
If the Prepared property of the Command object is set to True and the Command object is bound to an open connection when you set the CommandText property, ADO prepares the query (that is, a compiled form of the query that is stored by the provider) when you call the Execute or Open methods.
As a workaround, either set cmd.CommandText or cmd.ActiveConnection after adding parameters.

Calling Oracle Stored procedure from VBA ADODB

Hi
I am trying to use a stored procedure in WORD VBA to retrieve some addresses using a stored procedure to populate a list field.
Private Sub txtCpny_AfterUpdate()
Dim rst As ADODB.Recordset
Dim cmd As ADODB.Command
Dim param1 As ADODB.Parameter
Dim param2 As ADODB.Parameter
Dim strCpny As String
strCpny = GetSearchString(Me.txtCpny) 'ie %Name%
Set cmd = CreateObject("ADODB.Command")
With cmd
.ActiveConnection = mcn
.CommandText = "LISTPARTNER_NAME"
.CommandType = adCmdStoredProc
Set param1 = .CreateParameter("RCT1", adInteger, adParamInputOutput, , Null)
Set param2 = .CreateParameter("firmaName", adVarChar, adParamInput, 50, strCpny)
.Parameters.Append param1
.Parameters.Append param2
Set rst = .Execute
End With
...Using the recordset here
rst.Close
Set param1 = Nothing
Set param2 = Nothing
Set cmd = Nothing
End Sub
The Stored Procedure looks as follows: The SQL should result in a recordset holding the matching Companies.
PROCEDURE LISTPARTNER_NAME (
firmaName IN VARCHAR2 DEFAULT NULL,
RCT1 IN OUT GLOBALPKG.RCT1
)
AS
BEGIN
OPEN RCT1 FOR
SELECT
...
FROM
...
WHERE
KNAG.NAME_ORG LIKE LISTPARTNER_NAME.firmaName
...
END LISTPARTNER_NAME
When the command is executed VB throws a RunTime Error
ORA-06550: Line 1, column 13:
PLS-00306: wrong number or types of arguments in call to
'LISTPARTNER_NAME'
ORA-06550: line 1, column 7:
PL/SQL: Statement ignored
In my opinion the I am doing something wrong wit the parameters. Ihave been trying various versions of setting the parameters with no luck
Any Clues?
Thanks
have a look at this thread, it may be of assistance
http://forums.oracle.com/forums/thread.jspa?threadID=360922
The only other thing I could suggest would be switching the order of the parameters (so they are in the same order -- I know ODP defaults to order but I am unsure of ADODB)
I have been successfully using this code in Access:
Function runAdo(sql As String, usr As String, pwd As String)
'by Patrick Honorez - www.idevlop.com ----- 09-nov-2012
'Purpose : run Oracle proc using ADO connection
Dim cn As ADODB.Connection
Dim rs As ADODB.Recordset
Set cn = New ADODB.Connection
cn.Open GetPersonalizedConnectStringADO(usr, pwd)
Set rs = New ADODB.Recordset
rs.Open sql, cn, adOpenStatic, adLockReadOnly
cn.Close
End Function
I rarely use ADO from Access, since I find DAO simpler to use, but in this case I had to execute some Oracle procs requiring a different UID, and creating a new DAO Querydef specifying different UID and PWD, did not work, perhaps due to the fact that Access keeps a cache of connections.
So I decided to use ADO for the second "user" and it works like a charm.