Pass an array of ADODB parameters to function? - vba

I am attempting to create my ADODBcommand and parameters in the calligng code, so that I can pass them into a generic SQL function, but I get an error when retrieving the parameter from the list:
Dim prm As ADODB.Parameter
Dim cmd As ADODB.Command
Dim ParameterList(0) As Variant
Value = Cells(3,3).Value
Set cmd = New ADODB.Command
Set prm = cmd.CreateParameter("#Field", adVarChar, adParamInput, 50)
cmd.Parameters.Append prm
cmd.Parameters("#Field").Value = Value
ParameterList(0) = prm
Call SQLFunc(Data, SQLStr, adCmdStoredProc, cmd, ParameterList)
.
.
sub SQLFunc(ByRef Data as Variant, SQLStr as String, CommandType As ADODB.CommandTypeEnum, ByRef cmd As ADODB.Command, ParamList As Variant)
.
.
.
If cmd.CommandType <> adCmdStoredProc Then
cmd.Execute
Else
'Append the parameters
For i = LBound(ParamList, 1) To UBound(ParamList, 1)
Dim TempParam As ADODB.Parameter
Set TempParam = ParamList(i)
cmd.Parameters.Append TempParam 'Error here
Next
Set Rst = cmd.Execute
Could anyone please advise how I can achieve this?

After
ParameterList(0) = prm
ParameterList(0) is Empty, to resolve this;
set ParameterList(0) = prm
I would also strongly type this so instead of variant use Dim ParameterList(0) As ADODB.Parameter
The error you see occurs because you already append the parameter to the command before calling SQLFunc, in which you illegaly attempt to do so again. Parameter names must be unique when bound to a command.
You could remove the binding and use;
Set prm = cmd.CreateParameter("#Field", adVarChar, adParamInput, 50)
prm.Value = Value
Then prm remains independent of cmd.

Related

VBA Access more than 2 CreateParameter

I need to create an Access program but I am having trouble.
Here is the problem.
When I type information as below picture, all of the information should be inserted to the Listbox. 'BlendID' and 'Blend Method' are same for all element and only 'Precursor's' information change. So when I typed two item of precursor, there need to be two rows but I only get 1 data in the list box.
(Precursor2's information should be inserted in listbox but it is not working now)
Here is my code
Private Sub AddToListBlend_Click()
Dim cmd As ADODB.Command
Dim conn As ADODB.Connection
Dim strConn As String
Dim par As ADODB.Parameter 'input
'Dim introw As Integer
'On Error GoTo errorhandle
'introw = ListBlend.ListIndex + 1
strConn = "DRIVER=SQL Server;SERVER=CHU-AS-0004;DATABASE=RTC_LaplaceD_DEV;Trusted_Connection=Yes;"
Set conn = New ADODB.Connection
conn.Open strConn 'open connection
If IsNull(TextRequestNo.value) Or TextRequestNo.value = "" Then
MsgBox ("Please select Request No first")
Else
Set cmd = New ADODB.Command
cmd.CommandText = "dbo.AddBlendPrac"
cmd.CommandType = adCmdStoredProc
cmd.ActiveConnection = conn
Set par = cmd.CreateParameter("#BlendID", adVarChar, adParamInput, 50, TextB10.value)
cmd.parameters.Append par
Set par = cmd.CreateParameter("#BlendMethod", adVarChar, adParamInput, 50, TextB11.value)
cmd.parameters.Append par
Set par = cmd.CreateParameter("#RequestID", adVarChar, adParamInput, 50, TextRequestNo.value)
cmd.parameters.Append par
Set par = cmd.CreateParameter("#SampleID", adVarChar, adParamInput, 50, TextB12.value)
cmd.parameters.Append par
Set par = cmd.CreateParameter("#WLocation", adVarChar, adParamInput, 50, WLocation1.value)
cmd.parameters.Append par
cmd.Execute
conn.Close 'close connection
Set conn = Nothing
Set cmd = Nothing
MsgBox "Succeeded"
List731.Requery
End If
End Sub
I am aware that I need to add Precursor2's information but I do not know how to do it. As you can see first information is inserted to the ListBox, but second one is not.
Would you please share your idea about this?

Call Oracle stored procedure with VBA using a refcursor

I have stored procedure in Oracle:
create or replace procedure testproc (articlenr in number, storenr in number, cweek in varchar, prc out sys_refcursor)
is begin
open prc for
select * from weekly_revenues
where
article = articlenr
and period = cweek
and store = storenr
;
end;
I can call that function perfectly with the following SQL code:
variable rc refcursor;
exec testproc(123,345,'201705',:rc);
print rc;
That code gives me all the sales data for article 123, store 345 in week 5 of 2017.
Now, I want to call that stored procedure from VBA and I've tried the following code:
Sub ConnectToOracle()
Dim cn As ADODB.Connection
Dim rs As ADODB.Recordset
Dim cmd As New ADODB.Command
Dim param1 As New ADODB.Parameter
Dim param2 As New ADODB.Parameter
Dim arr As Variant
connstr = "Provider=msdaora;Data Source=###;User Id=###;Password=###;"
Set cn = New ADODB.Connection
Set rs = New ADODB.Recordset
cn.Open connstr
cmd.CommandText = "testproc"
cmd.ActiveConnection = cn
cmd.CommandType = adCmdStoredProc
Set param1 = cmd.CreateParameter("articlenr", adInteger, adParamInput, , 47)
Set param2 = cmd.CreateParameter("storenr", adInteger, adParamInput, , 281)
Set param3 = cmd.CreateParameter("cweek", adVarChar, adParamInput, 10, "201705")
Set param4 = cmd.CreateParameter("prc", adVariant, adParamOutput, , Null)
cmd.Parameters.Append param1
cmd.Parameters.Append param2
cmd.Parameters.Append param3
cmd.Parameters.Append param4
Set rs = cmd.Execute
arr = rs.GetRows
'Work with array...
End Sub
However, I get an arrow for the
Set rs = cmd.Execute
line ("ORA-0136: illegal variable name/number"). Does anyone know how I can get my code to run? I'm not sure whether the variable for the refcursor needs to be declared in a different way (as in the second code snippet), but I'm not sure whether that is the mistake or not.
Thanks!
I found a solution by accident.
If I don't define the ref_cursor parameter, it works.
cmd.CommandText = "testproc"
cmd.ActiveConnection = cn
cmd.CommandType = adCmdStoredProc
Set param1 = cmd.CreateParameter("articlenr", adInteger, adParamInput, , 47)
Set param2 = cmd.CreateParameter("storenr", adInteger, adParamInput, , 281)
Set param3 = cmd.CreateParameter("cweek", adVarChar, adParamInput, 10, "201705")
'Next line not needed
'Set param4 = cmd.CreateParameter("prc", adVariant, adParamOutput, , Null)
cmd.Parameters.Append param1
cmd.Parameters.Append param2
cmd.Parameters.Append param3
'Next line not needed
'cmd.Parameters.Append param4
Set rs = cmd.Execute
This works, apparently the ref_cursor specification is not needed and happens by default :)
Try this one:
Cmd.Properties ("PLSQLRSet") = TRUE
Set rs = cmd.Execute
arr = rs.GetRows
'Work with array...

ADODB.Command.Execute not working with parameter

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

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

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.