Excel VBA SQL query ADODB - excel

Hi I have an existing Excel sheet with some data inside, and now I want to perform queries directly from VBA. This is what I have now:
Private Sub CommandButton1_Click()
Dim sSQLQry As String
Dim ReturnArray
Dim Conn As New ADODB.Connection
Dim mrs As New ADODB.Recordset
Dim DBPath As String, sconnect As String
Dim newSheet As Worksheet
'DBPath = ThisWorkbook.FullName
DBPath = "C:\someData.xlsm"
sconnect = "Provider=MSDASQL.1;DSN=Excel Files;DBQ=" & DBPath & ";HDR=Yes';"
Conn.Open sconnect
sSQLSting = "SELECT username,count(username) FROM [Sheet1$] group by username order by count(username) desc;"
mrs.Open sSQLSting, Conn
Set newSheet = Sheets.Add
ActiveSheet.Range("A1").CopyFromRecordset mrs
mrs.Close
Conn.Close
End Sub
This query performs well and gives the desired result, but when I change it to this one:
Select param0,count(param0) From [Sheet1$] where eventid='addToCart' group by param0 order by count(param0) desc;
Because the param0 is like this: most of them are numbers, but some of them are numbers and characters mixed together, so the query result only returns the pure-number entries. So how can I configure the database so that it recognizes the param0 field should be text, instead of int? Also, when I perform this query:
Select eventid,param0,param1,count(*) From [Sheet1$] where eventid='search' group by param0, param1 order by count(*) desc;
It gives 'automation error'. I searched for it but could not get a suitable solution. Can anyone help with this? Thank you!
Edit: all the three queries give correct results in MySQL workbench. Now I need to perform the query directly in Excel sheet.

Your second problem lies within the fact that you are asking for the eventid field without including it within the aggregate GROUP BY clause.
SELECT eventid, param0, param1, count(*)
FROM [Sheet1$]
WHERE eventid='search'
GROUP by eventid, param0, param1
ORDER BY COUNT(*) DESC;
I ran your repaired queries against some sample data that I made up and came up with this.
Sub grp_param()
Dim cnx As Object, rs As Object, rs1 As Object
Dim sWS1 As String, sWS2 As String, sWB As String, sCNX As String, sSQL As String
Dim ws1TBLaddr As String
ws1TBLaddr = Worksheets("Sheet4").Cells(1, 1).CurrentRegion.Address(0, 0)
sWS1 = Worksheets("Sheet4").Name
sWB = ThisWorkbook.FullName
'for 64-bit Office
'sCNX = "Provider=Microsoft.Jet.OLEDB.12.0;Data Source=" & sWB _
& ";Extended Properties=""Excel 8.0;HDR=Yes;IMEX=1"";"
'for 32-bit or 64-bit Office
sCNX = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & sWB _
& ";Extended Properties=""Excel 8.0;HDR=Yes;IMEX=1"";"
Debug.Print sCNX
Set cnx = CreateObject("ADODB.Connection")
Set rs = CreateObject("ADODB.Recordset")
Set rs1 = CreateObject("ADODB.Recordset")
cnx.Open sCNX
'Select param0,count(param0) From [Sheet1$] where eventid='addToCart'
' group by param0 order by count(param0) desc;
sSQL = "SELECT param0, COUNT(param0) " & _
"FROM [" & sWS1 & "$" & ws1TBLaddr & "] " & _
"GROUP BY param0 " & _
"ORDER BY count(param0) DESC;"
Debug.Print sSQL
rs.Open sSQL, cnx
With Worksheets.Add(after:=Sheets(Sheets.Count))
.Name = "Summary Data"
.Range("A1").Resize(1, 2) = Array("param0", "count")
.Range("A2").CopyFromRecordset rs
End With
'Select eventid,param0,param1,count(*) From [Sheet1$] where eventid='search'
'group by param0, param1 order by count(*) desc;
sSQL = "SELECT eventid, param0, param1, COUNT(*) " & _
"FROM [" & sWS1 & "$" & ws1TBLaddr & "] " & _
"GROUP BY eventid, param0, param1 " & _
"ORDER BY count(param0) DESC;"
Debug.Print sSQL
rs1.Open sSQL, cnx
With Worksheets(Sheets.Count)
.Range("E1").Resize(1, 3) = Array("eventid", "param0", "count")
.Range("E2").CopyFromRecordset rs1
End With
rs.Close: Set rs = Nothing
rs1.Close: Set rs1 = Nothing
cnx.Close: Set cnx = Nothing
End Sub
I'm unclear on why mySQL allows that last query but my background is in T-SQl and it would certainly choke on that.

For the first confusion, I noticed the post here: link , but I don't want to add in another file for processing, so in the end no other choice, I pre-process the file by adding in 4 lines of texts right below the header line. (As in my case all fields can be text; I did this in MySQL) As the amount of data is quite big, these dummy texts don't affect the result yet help me produce the DB correctly.

Related

Using 'Insert Into' SQL Statement with column names on Excel Worksheet with ACE OLEDB fails

So, I want to get disciplined in how I store data to worksheets and was wanting to use the SQL OLEDB Provide for Excel and standard SQL statements. Insert into with column names does not work, yet, for me at least. Some code demonstrates the problem. Expecting both forms shown here to work W3 Schools SQL INSERT INTO Statement
Option Explicit
Sub MinimalCompleteVerifiableExample()
'Tools->References "Microsoft ActiveX Data Objects 2.8 Library"
Dim wsNew As Excel.Worksheet
Set wsNew = ThisWorkbook.Worksheets.Add
wsNew.Cells(1, 1) = "TimeStamp"
wsNew.Cells(1, 2) = "Path"
Dim oConn As ADODB.Connection
Set oConn = New ADODB.Connection
Debug.Assert UBound(Split(ThisWorkbook.Name, ".")) > 0 '* Workbook needs to be saved
oConn.Open "Provider=Microsoft.ACE.OLEDB.12.0;" & _
"Data Source=" & ThisWorkbook.FullName & ";" & _
"Extended Properties='Excel 12.0 Macro'"
Dim rsTestRead As ADODB.Recordset
Set rsTestRead = New ADODB.Recordset
rsTestRead.Open "Select * from [" & wsNew.Name & "$] AS P", oConn, adOpenStatic
Debug.Assert oConn.Errors.Count = 0
Debug.Assert rsTestRead.Fields.Item(0).Name = "TimeStamp"
Debug.Assert rsTestRead.Fields.Item(1).Name = "Path"
Dim sSQL As String
sSQL = "insert into [" & wsNew.Name & "$] (TimeStamp,Path) VALUES ('31-Dec-2015','C:\temp');" 'DOES NOT WORK
'sSQL = "insert into [" & wsNew.Name & "$] values ('25-Dec-2015','C:\temp')" 'works
Stop
oConn.Execute sSQL
Debug.Assert oConn.Errors.Count = 0
Stop
End Sub
On gets an error message of "Syntax error in INSERT INTO statement."
Ah.
It seems one adds square brackets around the column names
Dim sSQL As String
sSQL = "insert into [" & wsNew.Name & "$] ([TimeStamp],[Path]) VALUES ('31-Dec-2015','C:\temp');"

Error No value given for one or more required parameters with VBA

I am getting "No value given for one or more required parameters", I am new in Excel VBA, Please suggest what is wrong with the query, Below is the code I am using to get the value from a access data based and I want to have the table name and the table column name on runtime.
Dim con As ADODB.Connection
Dim rs As New ADODB.Recordset
Dim name As String
Dim count As Integer
Dim FindString As String
Dim FindString1 As String
Dim SQLQuery As String
FindString = InputBox("Enter the table name")
FindString1 = InputBox("Enter search value")
count = 4
Dim strConn As String
Set con = New ADODB.Connectioncon.Mode = adModeReadWrite
If con.State = adStateClosed Then
strConn = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & "databasepath\Database3.accdb;Persist Security Info=False;"
con.ConnectionString = strConn
con.Open
Set rs.ActiveConnection = con
End If
SQLQuery = "select * from " & FindString & " where " & FindString & ".[LOGO] ='" & FindString1 & "'"
rs.Open SQLQuery
Looks like a problem with this SQL query.
"select * from " & FindString & " where [Resolution] = '" & FindString1 & "'"
I would suggest to make an extra step like this.
Dim SQLQuery as String
SQLQuery = "select * from [" & FindString & "] where [Resolution] = '" & FindString1 & "'"
rs.Open SQLQuery
Maybe you can have a look at this solution too.
No value given for one or more required parameters visual basic error

Import to Excel from Access table based on two parameters

I am trying to import data from Access to Excel based on two parameters. I have a list of tools which specify a project number (parameter 1) and a tool type (parameter 2). How can I filter out the tools that don't satisfy the user's input of these two parameters?
I saw this thread: Import to Excel from Access table based on parameters
but it doesn't talk about multiple parameters. Here is where I am at so far:
Dim cn As Object
Dim rs As Object
Dim strFile As String
Dim strCon As String
Dim strSQL As String
Dim s As String
Dim i As Integer, j As Integer
''Access database
strFile = "D:\Tool_Database\Tool_Database.mdb"
''This is the Jet 4 connection string, you can get more
''here : http://www.connectionstrings.com/excel
strCon = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & strFile & ";"
''Late binding, so no reference is needed
Set cn = CreateObject("ADODB.Connection")
Set rs = CreateObject("ADODB.Recordset")
cn.Open strCon
'Find the name of the tool that was selected
Dim SelectedTool As String, SelectedProj
Set SelectedTool = Tools_ListBox.Selected
Set SelectedProj = Project_ListBox.Selected
strSQL = "SELECT * " _
& "FROM ToolFiles " _
& "WHERE Tool_Name = '" & SelectedTool & "'"
rs.Open strSQL, cn, 3, 3
Worksheets("ToolList").Cells(2, 1).CopyFromRecordset rs
rs.Close
Set rs = Nothing
cn.Close
Set cn = Nothing
Obviously the strSQL statement is where I need to get focused and insert the value into SelectedProj.
Thanks!
If you just wanted to add the SelectedProj to the SQL statement, this should be the trick (where ProjectType is the name of the field):
strSQL = "SELECT * " _
& "FROM ToolFiles " _
& "WHERE Tool_Name = '" & SelectedTool & "' " _
& "AND ProjectType = '" & SelectedProj & "'"
The selected property returns True if the item is selected which doesn't make sense in your example above. Perhaps you are looking for something like
SelectedTool = Tools_listbox.Items(Tools_listbox.SelectedItem)
Note you also do not have a declaration for SelectedTool which is naughty but I guess it should be a string in which case you should not use the Set.

Run access query from Excel and pass parameters to the query

How to execute a query in MS Access db from Excel VBA code or macro.
MS-Access query accepts some parameters, that needs to be passed from Excel.
Thanks
Here is one possibility:
Dim cn As Object
Dim strFile As String
Dim strCon As String
Dim strSQL As String
strFile = "C:\docs\Test.mdb"
strCon = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & strFile
''Late binding, so no reference is needed
Set cn = CreateObject("ADODB.Connection")
cn.Open strCon
strSQL = "INSERT INTO ATable (AField) " _
& "VALUES (" & Sheet1.[A1] & ")"
cn.Execute strSQL
cn.Close
Set cn = Nothing
You can also refer in-line in the sql to a dataset from Excel.
EDIT re comments
Using a command:
strSQL = "SELECT * FROM ATable " _
& "WHERE AField = #AField"
With cmd
Set .ActiveConnection = cn
.CommandText = strSQL
.CommandType = 1 'adCmdText
''ADO Datatypes are often very particular
''adSmallInt = 2 ; adParamInput = 1
.Parameters.Append .CreateParameter("#AField", 2, 1, , Sheet1.[A1])
End With
Set rs = cmd.Execute
See also: http://support.microsoft.com/kb/181782
This uses ADODB.
Set m_Connection = New Connection
If Application.Version = "12.0" Then
m_Connection.Provider = "Microsoft.ACE.OLEDB.12.0"
Else
m_Connection.Provider = "Microsoft.Jet.OLEDB.4.0"
End If
m_Connection.Open <full path to Access DB>
If m_Connection.State > 0 Then
Dim rsSource As New Recordset
rsSource.Open strQuery, m_Connection, adOpenForwardOnly, adLockReadOnly
Dim result As Long
Dim rngTarget As Range
rngTarget = ThisWorkbook.Worksheets(m_SheetName).Range("A1")
If Not rsSource.BOF Then
result = rngTarget.CopyFromRecordset(rsSource)
End If
If rsSource.State Then rsSource.Close
Set rsSource = Nothing
End If
So it runs the query and puts it where you like. strQuery is the name of a query in the db or an SQL string.

Updating MS - Access fields through MS-Excel cells

Consider that I have an Excel workbook and an Access table not necessarily having a similar structure (i.e. they may not have same number of columns).
When I open the workbook the rows in the Excel sheet get populated by the rows in Access table (copied from the Access table into the Excel sheet's particular range of cells specified using macros).
Then I modify certain cells in the Excel sheet.
I also have a button called "Save" in the Excel sheet. When pressed, this will execute a macro.
My question: how can I update the Access table to reflect the changes in the Excel sheet when the "Save" button is clicked?
You can use ADO and some code.
Here are some notes.
Let us say you get some data like so:
Sub GetMDB()
Dim cn As Object
Dim rs As Object
strFile = "C:\Docs\DBFrom.mdb"
strCon = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & strFile & ";"
Set cn = CreateObject("ADODB.Connection")
Set rs = CreateObject("ADODB.Recordset")
cn.Open strCon
strSQL = "SELECT * FROM Table1"
rs.Open strSQL, cn
With Worksheets(7)
For i = 0 To rs.Fields.Count - 1
.Cells(1, i + 1) = rs.Fields(i).Name
Next
rs.MoveFirst
.Cells(2, 1).CopyFromRecordset rs
End With
End Sub
You could update the data using ADO like so:
Sub UpdateMDB()
Dim cn As Object
Dim rs As Object
''It wuld probably be better to use the proper name, but this is
''convenient for notes
strFile = Workbooks(1).FullName
''Note HDR=Yes, so you can use the names in the first row of the set
''to refer to columns
strCon = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & strFile _
& ";Extended Properties=""Excel 8.0;HDR=Yes;IMEX=1"";"
Set cn = CreateObject("ADODB.Connection")
Set rs = CreateObject("ADODB.Recordset")
cn.Open strCon
''Selecting the cell that are different
strSQL = "SELECT * FROM [Sheet7$] s " _
& "INNER JOIN [;Database=c:\Docs\DBFrom.mdb;].Table1 t " _
& "ON s.id=t.id " _
& "WHERE s.Field1<>t.Field1"
rs.Open strSQL, cn, 1, 3 ''adOpenKeyset, adLockOptimistic
''Just to see
''If Not rs.EOF Then MsgBox rs.GetString
''Editing one by one (slow)
rs.MoveFirst
Do While Not rs.EOF
rs.Fields("t.Field1") = rs.Fields("s.Field1")
rs.Update
rs.MoveNext
Loop
''Batch update (faster)
strSQL = "UPDATE [;Database=c:\Docs\DBFrom.mdb;].Table1 t " _
& "INNER JOIN [Sheet7$] s " _
& "ON s.id=t.id " _
& "SET t.Field1=s.Field1 " _
& "WHERE s.Field1<>t.Field1 "
cn.Execute strSQL
End Sub

Resources