Export data to Access from Excel VBA - excel

I am brand new to access and struggling to understand how to relate access table/column/row formatting to excel exporting in VBA.
I have created an access table called Data and three columns Food, Drinks, Color.
I would like to export these range of cells to Access from my excel spreadsheet:
Foodrng = Workbooks(xlFile).Sheets("ToBeExported").Range("D6")
Drinksrng = Workbooks(xlFile).Sheets("ToBeExported").Range("E6")
Colorrng= Workbooks(xlFile).Sheets("ToBeExported").Range("B12:B21")
Everything online says I should use this for because of my version:
strConnection = "Provider=Microsoft.ACE.OLEDB.12.0;"
I would like to use INSERT TO formatting to write to my database because I will be expanding the database columns quite a bit, and I feel this is the easiest way to keep track of which is going where.
strSql = "INSERT INTO Data (Food, Drinks, Color) VALUES (Foodrng, Drinksrng,Colorrng)"
I always get a syntax error when executing:
Set rs = cn.Execute(strSql)
What is the correct way to export to the Access database using the above method? Any/all information will be super helpful as I am brand new to Access
My full code:
Foodrng = Workbooks(xlFile).Sheets("ToBeExported").Range("D6")
Drinksrng = Workbooks(xlFile).Sheets("ToBeExported").Range("E6")
Colorrng= Workbooks(xlFile).Sheets("ToBeExported").Range("B12:B21")
Set cn = CreateObject("ADODB.Connection")
strConnection = "Provider=Microsoft.ACE.OLEDB.12.0;" & _
"Data Source= C:\Users\User1\MyDBase.accdb"
cn.Open strConnection
strSql = "INSERT INTO Data (Food, Drinks, Color) VALUES (Foodrng, Drinksrng,Colorrng)"
Set rs = cn.Execute(strSql)
'MsgBox rs.Fields(0) & " rows in MyTable"
rs.Close
Set rs = Nothing
cn.Close
Set cn = Nothing

When inserting using queries, you need to pass values using parameters. I highly recommend using recordsets over insert queries.
A normal insert query can only insert one row at a time. You will need to adjust the code to insert one row at a time. You can either use a recordset, or execute a query for each row.
Foodrng = Workbooks(xlFile).Sheets("ToBeExported").Range("D6") 'Adjust ranges to select single cells
Drinksrng = Workbooks(xlFile).Sheets("ToBeExported").Range("E6")
Colorrng= Workbooks(xlFile).Sheets("ToBeExported").Range("B12:B21")
Set cn = CreateObject("ADODB.Connection")
strConnection = "Provider=Microsoft.ACE.OLEDB.12.0;" & _
"Data Source= C:\Users\User1\MyDBase.accdb"
cn.Open strConnection
strSql = "INSERT INTO [Data] ([Food], [Drinks], [Color]) VALUES (?, ?, ?)"
Dim cmd As ADODB.Command
Set cmd = New ADODB.Command
With cmd
Set .ActiveConnection = cn
.CommandText = strSql
.Parameters.Append .CreateParameter(, adVarWChar, adParamInput, , foodRng) 'adVarWChar for text
.Parameters.Append .CreateParameter(, adInteger, adParamInput, , Drinksrng) 'adInteger for whole numbers (long or integer)
.Parameters.Append .CreateParameter(, adInteger, adParamInput, , Colorrng)
.Execute
End With
cn.Close

There maybe also another way, or two, perhaps worth consideration.
The first would be to set up your Excel spreadsheet as a linked table in Access - maybe it can be done with VBA. This would save you the requirement to copy the data. You might also be able to set up your target worksheet and use insert..select directly from ADODB to insert the data into Excel from Access.
The second, would be to completely avoid Access altogether if your requirements allow for this. Excel can be used as a database to some extent and supports SQL querying.
https://selectcompare.com/blogs/news/write-select-statements-for-excel-spreadsheets

Related

How to join two excel worksheets based on a column as key using VBA

I am not sure what approach to take but wondering can I join data from two excel sheets and populate in a 3rd sheet like how we join in SQL using VBA. Example data is below, I would like to join Sheet1 and Sheet2 by Emp_id and populate the result in Sheet3. I have googled a lot and tried whatever I know but nowhere I am close to get this, can someone throw some light on this or share an working example, that would be great. I am still trying and will post if I got a solution.
Below works for mine, again below query is for the sample data. For my actual data, I had to get the sheet number to use sheet name (example [Sheet2$] is replaced with [Sheet" & Sheets("Source").Index & "$] to use "Source" as the sheet in place of "Sheet2".
I have to use LEFT JOIN because I am getting error with only JOIN and later deleted the extra rows from Sheet3 for the records not matching in Sheet1, also you may have to use UNION function since FULL JOIN is not supported in case if you want data from both the table.
Hope this helps for someone...
Option Explicit
Sub JoinTables()
Dim cn As ADODB.Connection
Set cn = New ADODB.Connection
With cn
.Provider = "Microsoft.Jet.OLEDB.4.0"
.ConnectionString = "Data Source=" & ThisWorkbook.Name & ";" & _
"Extended Properties=Excel 8.0;"
.Open
End With
Dim rs As ADODB.Recordset
Set rs = New ADODB.Recordset
rs.Open "SELECT * FROM [Sheet2$] LEFT JOIN [Sheet1$] ON [Sheet2$].[Emp_id] = [Sheet1$].[Emp_id]", cn
With Worksheets("Sheet3")
.Cells(2, 1).CopyFromRecordset rs
End With
rs.Close
cn.Close
End Sub
cn As New ADODB.Connection
rec As New ADODB.Recordset
cn.ConnectionString = "Driver={Microsoft Excel Driver (*.xls, *.xlsx, *.xlsm, *.xlsb)};DBQ=" & _
ActiveWorkbook.Path & Application.PathSeparator & ActiveWorkbook.Name
SQLquery = "SELECT [Sheet2$].[Emp_id],[Sheet2$].[Hobies],[Sheet1$].[Salary] FROM [Sheet2$] INNER JOIN [Sheet1$] ON [Sheet2$].[Emp_id]=[Sheet1$].[Emp_id]"
rec.Open SQLquery, cn, adOpenKeyset, adLockOptimistic
Sheets("Sheet3").Range("A1").CopyFromRecordset rec

Excel VBA - how to query Access database using column values as a parameter?

I have an Excel worksheet that has a list of about 1000 Item Numbers in column A on Sheet1. Currently, I import Sheet1 into an Access table named ItemNumbers and run the following query:
SELECT MyTable.ItemNumber, MyTable.ItemName, MyTable.ItemPrice
FROM [ItemNumbers] INNER JOIN MyTable ON [ItemNumbers].ItemNumber = MyTable.ItemNumber
ORDER BY MyTable.ItemNumber;
And then I copy/paste the output to Sheet2.
How can I do this in VBA in Excel and put the results in a recordset? I can figure out how to loop through the recordset and put the results in Sheet2. I'm just not sure on the code to run the query.
I have the following so far. It just needs to be modified to use the values in Sheet1 Column A.
Dim cn As Object
Dim rs As Object
Dim strSql As String
Dim strConnection As String
Set cn = CreateObject("ADODB.Connection")
strConnection = "Provider=Microsoft.ACE.OLEDB.12.0;" & _
"Data Source=C:\MyDatabase.accdb"
strSql = "SELECT MyTable.ItemNumber, MyTable.ItemName, MyTable.ItemPrice " & _
"FROM MyTable " & _
"WHERE WHERE (((MyTable.ItemNumber)= ??? IS IN Sheet1!A:A ??? )) " & _
"ORDER BY MyTable.ItemNumber;"
cn.Open strConnection
Set rs = cn.Execute(strSql)
rs.Close
Set rs = Nothing
cn.Close
Set cn = Nothing
Thanks!!!
If I understand right; what you ask is to join a table from Access with a table in Excel (ADODB).
Check this link from SO, and see if it's helpful:
Selecting 2 tables from 2 different databases (ACCESS)
I haven't tried to combine Access and Excel before, but my guess is that it will work for Excel as well.
An alternate way (and that will certainly work):
Run the query without the WHERE clause and store the result in a
recordset;
Store the data from the Excel sheet that you require in a dictionary,
where the ItemNumber (PK?) is the key;
Run through the recordset, and check with the typical dictionary Exists function
if the ItemNumber from each record is available in the dictionary;
If the record is availabe, store the
recordset values in a separate array (or dictionary) that you can
use for further manipulation, (or perform direct actions if that's what you want to do).

Is it possible to create a VBA QueryTable outer join between a CSV file and a worksheet?

I'm creating an excel workbook to manage my personal finances. My banks provide transaction data in CSV format and I found a way to import that data into excel using a QueryTable (using a "TEXT" connection.)
I'd like to automatically apply transaction category rules to each imported transaction. I have a worksheet with two columns - a string to match against the transaction "details" provided in my bank's CSV file and the category to apply to the matching transactions.
Is it possible to create an outer join between the CSV data and the categories worksheet and dump the resulting table into another worksheet?
For example (SQL pseudocodeish): SELECT csv.date, csv.details, csv.debit, csv.credit, ws.category FROM [csvfile] csv LEFT OUTER JOIN [worksheet] ws ON csv.details ~= ws.details
~= above would be some kind of string match. I can figure out the SQL, my question is really how to combine the CSV file and worksheet in the same QueryTable.
Excel will open CSV files without blinking, but you can use a connection string, if you prefer. It is even possible to write a query that compares an existing worksheet or named range with a text file using an Excel connection. All you need is a little VBA.
Set cn = CreateObject("ADODB.Connection")
Set rs = CreateObject("ADODB.Recordset")
'Note HDR=Yes, that is, first row contains field names '
'and FMT delimted, ie CSV '
strCon="Provider=Microsoft.Jet.OLEDB.4.0;Data Source=c:\Docs\;" _
& "Extended Properties=""text;HDR=Yes;FMT=Delimited"";"
cn.open strcon
'You would not need delimiters ('') if last field is numeric: '
strSQL="SELECT FieldName1, FieldName2 FROM The.csv " _
& " WHERE LastFieldName='SomeTextValue'"
rs.Open strSQL, cn
Worksheets("Sheet3").Cells(2, 1).CopyFromRecordset rs
You can use any suitable Jet SQL queries against the connection, just be careful about case sensitivity. For example, working with a connection to the current workbook:
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
''This is not the best way to refer to the workbook
''you want, but it is very convenient for notes
''It is probably best to use the name of the workbook.
strFile = ActiveWorkbook.FullName
''Note that if HDR=No, F1,F2 etc are used for column names,
''if HDR=Yes, the names in the first row of the range
''can be used.
''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 _
& ";Extended Properties=""Excel 8.0;HDR=Yes;IMEX=1"";"
''Late binding, so no reference is needed
Set cn = CreateObject("ADODB.Connection")
Set rs = CreateObject("ADODB.Recordset")
cn.Open strCon
strSQL = "SELECT * " _
& "FROM [Sheet1$] a " _
& "LEFT JOIN [Text;FMT=Delimited;HDR=Yes;" _
& "DATABASE=C:\Docs].Import.txt b " _
& "ON a.[Id]=b.[Id] "
rs.Open strSQL, cn, 3, 3
''Pick a suitable empty worksheet for the results
Worksheets("Sheet3").Cells(2, 1).CopyFromRecordset rs
''Tidy up
rs.Close
Set rs = Nothing
cn.Close
Set cn = Nothing
It is possible to create an OUTER JOIN referencing disparate data sources (csv, Excel, Access, txt, SQL, Oracle, etc) using ISAM Names in an ADO query. The results are held in a recordset that can be published back to Excel or another datasource as desired. Google "SQL ISAM Names" to find my other posts on the topic.
I am sure a little more info would help clear up my confusion but I don't believe it is possible to set up a SQL query against a CSV as Excel will not recognise it as a Data Source.
Have you thought about simply loading the csv into Excel and generating a pivot table/lookups on the data?

Using "SELECT SCOPE_IDENTITY()" in ADODB Recordset

Using a VBA script in Excel, I'm trying to insert a new row into a table and then get back the identity value of that row. If I run:
INSERT INTO DataSheet(databaseUserID, currentTimestamp)
VALUES (1, CURRENT_TIMESTAMP);
SELECT SCOPE_IDENTITY()
in Management Studio, the row is inserted and it gives me the returned identity value as expected. However, when I run the exact same query through a ADODB recordset in VBA, I'm having trouble. The row is indeed inserted, but I can't access the identity value. The recordset lists 0 fields and has actually been closed as well. I've tried with and without the semicolon, and I also tried running the query as a single transaction as well. Same deal, no dice. Any idea what is going on?
Here's my VBA:
Dim rs As ADODB.Recordset
Dim cn As Connection
Dim SQLStr As String
Dim serverName As String
Dim databaseName As String
serverName = "MSSQLServer"
databaseName = "QA"
cxnStr = "Driver={SQL Server};Server=" & serverName & ";Database=" & databaseName & ";"
SQLStr = "INSERT INTO DataSheet(databaseUserID, currentTimestamp)
VALUES (1, CURRENT_TIMESTAMP); SELECT SCOPE_IDENTITY()"
Set cn = New ADODB.Connection
cn.Open cxnStr
Set rs = New ADODB.Recordset
rs.Open SQLStr, cn, adOpenKeyset, adLockOptimistic
MsgBox (rs.Fields(0).Value)
And the message box fails to display because the rs.Fields(0).Value returns NULL. I added a watch to rs, and, like I said, shows 0 fields after the query and also appears to be closed (state = 0).
When you run a batch of commands using ADODB, I believe it runs each one seperately. To force the next command to run, you have to use the following:
Set rs = rs.NextRecordset()
Changing the end of your routine to the following should do the trick:
Set rs = New ADODB.Recordset
rs.Open SQLStr, cn, adOpenKeyset, adLockOptimistic
Set rs = rs.NextRecordset
MsgBox (rs.Fields(0).Value)
You are executing two statements so you will get two results back. the recordset object can only hold one result at a time - to get the other result you need to use the NextRecordset method.
Set rs = rs.NextRecordset
In your rs.Open Try this
rs.Open SQLStr, cn, adCmdText
See what happens when you remove the adOpenKeySet and adLockOptimistic values leave them at their defaults.

Clearing a table

What I'm trying to do is, while in Excel, use VBA to push data to an existing Access table. I've been able to do this, but am having one small hiccup. Before I push the data to access, I want to clear the current data on the Access table, so when the new data from Excel comes in, it is the only data in the Access table. I really don't know how to write code for Access since the class has been on VBA for Excel. I've tried several different approaches and each time it doesn't work. For example, the code that seemed like it should work is
DoCmd.RunSQL "DELETE tblName.* FROM CoversheetTableFourthAttempt
but I get an error telling me to define an object.
If you could help me with this, I would really appricate it
I've put my code below for reference.
Sub AccessFourthMonth()
Dim cn As ADODB.Connection, rs As ADODB.Recordset, r As Long
' connect to the Access database
Set cn = New ADODB.Connection
cn.Open "Provider=Microsoft.Jet.OLEDB.4.0; " & _
"Data Source=C:\Users\Kent\Documents\MBA\Winter 2009 Semester\MBA 614\Final Project\shilded\testdatabase.mdb"
' open a recordset
Set rs = New ADODB.Recordset
rs.Open "CoversheetTableFourthAttempt", cn, adOpenKeyset, adLockOptimistic, adCmdTable
' all records in a table
r = 2 ' the start row in the worksheet
Do While Len(Range("A" & r).Formula) > 0
' repeat until first empty cell in column A
With rs
.AddNew ' create a new record
' add values to each field in the record
.Fields("Project") = Range("A" & r).Value
.Fields("Description") = Range("B" & r).Value
.Fields("Amount") = Range("C" & r).Value
.Fields("Date") = Range("D" & r).Value
.Update ' stores the new record
End With
r = r + 1 ' next row
Loop
rs.Close
Set rs = Nothing
cn.Close
Set cn = Nothing
End Sub
Try
DoCmd.RunSQL "DELETE * FROM TableName"
This article might be of interest: Executing SQL Statements in VBA Code
Try the following from Excel:
dim cn as adodb.connection
dim cmd as adodb.command
set cn = new adodb.connection
cn.open "put your connection string here"
set cmd = new adodb.command
cmd.commandtype = adcmdtext
cmd.commandtext = "Delete * from myTable"
cmd.activeconnection = cn.connectionstring
cmd.execute
DoCmd is internal to Access application and not recognized by Excel application.
Simple approach to your problem is to fire the delete query from Excel itself.
Add this part after your cn.Open "Provider.. line
cn.Execute "DELETE * FROM CoversheetTableFourthAttempt"
This should clear the table before next part which fills the data runs.
Your DoCmd approach has two problems. You used a quote to start a string, but didn't include a closing quote. But even with proper quoting, your DoCmd won't work because Excel does not know that CoversheetTableFourthAttempt is the name of a table in an Access database.
You showed that you can successfully create an ADO connection to your Access database. So my suggestion is to use the Execute method of the connection object to execute your SQL statment:
cn.Execute "DELETE FROM CoversheetTableFourthAttempt;"
Finally, visit Problem names and reserved words in Access to understand why Date, Description, and Project are not great choices for Access field names.

Resources