VBA, ADO.Connection and query parameters - vba

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.

Related

VBA ADODB parameter as dynamic Excel Range

I'm trying to pass a list of parameters to a SQL query in VBA, I have an excel table with a list of codes in a range that is dynamic, could 2, could be 2000. I want to then return all data from SQL where the codes match. Below I'm trying to define an ADODB parameter as an array, then I want to pass that to SQL.
However defining the parameter variable as a range gives a type mismatch. Or Object required if I don't define as an array;
Dim conn As New ADODB.Connection
conn.Open "Provider=SQLOLEDB; Data Source=XXXXXXXXX; Initial Catalog=CDB; Integrated Security=SSPI;"
Dim code(0) As ADODB.Parameter
Set code(0) = wb.ActiveSheet.Range(Cells(2, colCode), Cells(rowCount, colCode)).Value
'Dim code As ADODB.Parameter
'Set code = wb.ActiveSheet.Range(Cells(2, colCode), Cells(rowCount, colCode)).Value
'Dim code(rowCount - 1) As ADODB.Parameter
'Set code(rowCount - 1) = wb.ActiveSheet.Range(Cells(2, colCode), Cells(rowCount, colCode)).Value
Set cmd = New ADODB.Command
Set rs = New ADODB.Recordset
With cmd
.ActiveConnection = conn
.CommandType = adCmdText
.Parameters.Append .CreateParameter("#code", adVarChar, adParamInput, 10000, code)
.CommandTimeout = 0
End With
sql = "SELECT * FROM table WHERE code in (?);"
cmd.CommandText = sql
Set rs = cmd.Execute

Insert Into Table from Excel via VB button to stored procedure with Variables

I have a simple table AMC_GW_TESTTABLE with two columns, name nvarchar(20) and phone nvarchar(12). I also have a simple stored procedure with two variables.
create procedure AMC_GW_TESTSP (#name nvarchar(20),
#phone nvarchar(12)) as
insert into AMC_GW_Testtable (name,phone)
values (#name, #Phone)
I have been able to get a button in Excel to create the command:
exec dbo.amc_gw_testsp 'fred' '620-555-1212'
But it does not execute it. I copy this to my SSMS exactly like it and execute it and it works fine. Any ideas?
VBA code
Sub Button1_Click()
Dim conn As ADODB.Connection
Dim cmd As ADODB.Command
Dim connStr As String
Dim param As ADODB.Parameter
Dim param2 As ADODB.Parameter
connStr = "Provider=SQLOLEDB.1;Integrated Security=SSPI;Persist Security Info=False;" _
& "Initial Catalog=am_app);Data Source=bcu-sql-01"
Set conn = New ADODB.Connection
conn.ConnectionString = connStr
conn.Open
Set cmd = New ADODB.Command
With cmd
.ActiveConnection = conn
.CommandType = adCmdStoredProc
.CommandText = "AMC_GW_TESTSP"
Set param = .CreateParameter("#name", adVarChar, adParamInput, 20, "Christopher")
.Parameters.Append param
Set param2 = .CreateParameter("#phone", adVarChar, adParamInput, 12, "0123456789")
.Parameters.Append param
.Execute
End With
conn.Close
Set cmd = Nothing
Set conn = Nothing
End Sub
I hope I did not scare you with a request for VBA Code
To give you an idea of what you should have:
Sub Button1_Click()
Dim conn As ADODB.Connection
Dim cmd As ADODB.Command
Dim connStr As String
Dim param As ADODB.Parameter
Dim param2 As ADODB.Parameter
connStr = "Provider=SQLOLEDB.1;Integrated Security=SSPI;Persist Security Info=False;" & _
"Initial Catalog=dbname;Data Source=servername"
Set conn = New ADODB.Connection
conn.ConnectionString = connStr
conn.Open
Set cmd = New ADODB.Command
With cmd
.ActiveConnection = conn
.CommandType = adCmdStoredProc
.CommandText = "AMC_GW_TESTSP"
Set param = .CreateParameter("#name", adVarChar, adParamInput, 20, "Christopher")
.Parameters.Append param
Set param2 = .CreateParameter("#phone", adVarChar, adParamInput, 12, "0123456789")
.Parameters.Append param
.Execute
End With
conn.Close
Set cmd = Nothing
Set conn = Nothing
End Sub
Things that you will have to change. Firstly the connection string (connStr). You will need to provide database name in place of dbname and server in place of servername. Also this string is assuming that you are using Windows Authentication for your SQL Server. If not you need to remove Integrated Security=SSPI; and in its place supply User ID=myUser;Password=myPassword;.
Next you will notice that the last parameter in the .CreateParameter function is a fixed string ("Christopher" and "0123456789"). In your case, they should be variables taken from cells in the spreadsheet. Please, please make sure that these strings do not contain ";" before trying to Execute.
I hope this helps, but feel free to contact me, if anything is less than clear!
PS You will need to make sure under Tools References, that you have the highest version of Microsoft ActiveX Data Objects Library checked (mine is 6.1, but anything 2.0 or higher definitely works).

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

Excel VBA executing SQL Server stored procedure - result set throwing error 3704

I am trying to execute a SQL Server stored procedure from Excel VBA. The procedure returns rows into a result set object. However, while running the code, it throws an error:
3704 Operation is not allowed when the object is closed
Note:
There is no problem with the database connection because Select query running on the same connection object are working fine.
Dim cn As ADODB.Connection
Dim rs As ADODB.Recordset
Dim cmd As ADODB.Command
Dim prm As ADODB.Parameter
Dim rst As New ADODB.Recordset
Set cn = New ADODB.Connection
Set cmd = New ADODB.Command
ThisWorkbook.initialize
cn.Provider = "sqloledb"
cn.Properties("Data Source").Value = ThisWorkbook.server
cn.Properties("Initial Catalog").Value = ThisWorkbook.db
cn.Properties("User ID").Value = "xxxxx"
cn.Properties("Password").Value = "xxxxx"
cn.Open
Set cmd = New ADODB.Command
cmd.CommandText = "Generate_KPI_Process_Quality_Check_RunTime"
cmd.CommandType = adCmdStoredProc
cmd.ActiveConnection = cn
Set prm = cmd.CreateParameter("#currentMonth", adChar, adParamInput, 255, cmb_month.Value)
cmd.Parameters.Append prm
Set prm = cmd.CreateParameter("#center", adChar, adParamInput, 255, cmb_center.Value)
cmd.Parameters.Append prm
rst.CursorType = adOpenStatic
rst.CursorLocation = adUseClient
rst.CursorLocation = adUseServer
rst.LockType = adLockOptimistic
rst.Open cmd
If (rst.BOF And rst.EOF) Then
'Some Code
End If
Put
SET NOCOUNT ON
in the stored procedure -- this will prevent output text generation like "1 record(s) updated".
You have to provide more parameters for the Open method of Recordset Object
try rst.Open cmd, cn
Use the Set keyword to assign the object:
Set cmd.ActiveConnection = cn
otherwise, the default property of the Connection object (which happen to be the connection string) will be assigned in lieu of the Connection object itself.
Just put another recordset that will contain resultsets
Dim rst1 As New ADODB.Recordset
SET rst1=rst.NextRecordset 'this will return the first resultset
If rst1.BOF or rst1.EOF Then...
'some code
End If