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.
Related
I have an Excel sheet with a command button, which opens an Access form and fills it with data from the sheet.
If I have two Access instances running (different databases) I get the message that VBA can not find the form.
Is it possible to address a specific database form?
Current Code: DoCmd.OpenForm ("FORM_ABC")
Not sure you need a Form to do this kind of thing. Here's one way to send data from Excel to Access.
Sub InsertIntoX2()
Dim cn As ADODB.Connection, rs As ADODB.Recordset, row As Long
Set cn = New ADODB.Connection
cn.Open "Provider=Microsoft.ACE.OLEDB.12.0; " & _
"Data Source=C:\Users\Excel\Desktop\Test.accdb;"
' open a recordset
Set rs = New ADODB.Recordset
rs.Open "tblTrx", cn, adOpenKeyset, adLockOptimistic, adCmdTable
row = 3 ' the start row in the worksheet
Do While Not IsEmpty(Worksheets("Sheet1").Range("A" & row))
With rs
.AddNew ' create a new record
.Fields("ID") = Worksheets("Sheet1").Range("A" & row).Value
.Fields("Product") = Worksheets("Sheet1").Range("B" & row).Value
.Fields("ProdDate") = Worksheets("Sheet1").Range("C" & row).Value
.Update
End With
row = row + 1
Loop
rs.Close
Set rs = Nothing
cn.Close
Set cn = Nothing
End Sub
If you want to use an Excel form to capture data and save the data to a Worksheet, and then send the results to Access, use the VBA code sample described above.
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
I'm putting together an Excel front-end with an Access database behind it, so that some of my colleagues can collate data from previous projects (without having to learn to use Access themselves!)
So I have a "Data" sheet in the Excel workbook that occasionally refreshes from the database, then a "Dashboard" sheet that allows filtering of that data.
Where I'm having trouble is in closing the loop - allowing input of new data into the database. The relevant code is below:
Private Sub btnDBImport_Click()
Dim rst As ADODB.Recordset
Dim errorList As String
Dim cn As ADODB.Connection
Set cn = New ADODB.Connection
With cn
.Provider = "Microsoft.ACE.OLEDB.16.0"
.ConnectionString = "\\FileAddress\DB.accdb"
.Open
End With
Set rst = New ADODB.Recordset
rst.CursorLocation = adUseServer
rst.Open Source:="TableName", _
ActiveConnection:=cn, _
CursorType:=adOpenDynamic, _
LockType:=adLockOptimistic, _
Options:=adCmdTableDirect
If validationTest = False Then
errorList = errorList & "Data at row " & i & " was not added to the database due to missing information." & vbCrLf
Else
rst.AddNew
With rst
.Fields(1) = Value1
.Fields(2) = Value2
End With
rst.Update
End If
Next i
If errorList <> "" Then
MsgBox errorList, vbOKOnly, "Data error"
End If
rst.Close
Set rst = Nothing
cn.Close
Set cn = Nothing
End Sub
The above is everything involved in defining, opening and working on a recordset; I get an error at rst.AddNew because "cannot update, database or object is ReadOnly".
Any help appreciated.
So, with thanks to the comment from Jimmy Smith, I've got to the bottom of this, or at least fixed my immediate problem.
The table was being treated as ReadOnly both when accessed through MS Access directly and when loaded as a Recordset using VBA because there was a link to the table in the same Excel workbook.
Now that I've deleted the link to the table and instead update the records in it through code, I'm consistently getting requested levels of access to the relevant table and everything is working as intended. Time to commit to Rubberduck and show it to the userbase.
I only have moderate experience when it comes to EXCEL VBA and ADO. I have two files a task file and a calendar file each of which is on a different database and a different server. I need to determine the number of actual work days associated to the task. So I need to take the timestamp date from the task file, check it against the calendar file to determine how many days in the task are actual working days. I figured out how to open two separate database connections in my VBA Script, but what I cannot figure out is how to combine the two files so I can get a working days count.
Something like this
Select Taskid, count(*)
From TaskFile, Calendar
Where TaskDate >= CalendarDate
And TaskDate <= CalendarDate
And CalendarWorkDay = 1
Group by Taskid
I thought about preloading a worksheet with the calendar data but don't see how the query will work.
Any suggestions or code snippets would be greatly appreciated.
This is a quick and dirty subroutine that will do something like what I suggested in the second comment above. It probably won't work exactly as you need it to right out of the box, but the overall idea is sound. Just realize that every record returned in the first query will generate a new query to the second file/database, so it could get pretty hairy if there are a lot of records.
Sub twoRecordsets()
Dim objConn As ADODB.Connection, objConn2 As ADODB.Connection
Dim rs As ADODB.Recordset
Dim strSQL As String
Dim strConn As String, strconn2 As String
'open first connection
Set objConn = New ADODB.Connection
strConn = "<your 1st connection string>"
objConn.Open strConn
'open second connection
Set objConn2 = New ADODB.Connection
strconn2 = "<your 2nd connection string>"
objConn2.Open strconn2
'first query:
strSQL = "Select Taskid, TaskDate From TaskFile GROUP BY TaskID"
'open first recordset using first query
Set rs = New ADODB.Recordset
rs.Open strSQL, objConn
'Die if there are no records returned
If rs.EOF And rs.BOF Then
Exit Sub
End If
'Loop through recordset
rs.MoveFirst
Do Until rs.EOF
'build a sql statement to do the second bit. might have to monkey with quote marks and date formats depending on DB
strSQL = "SELECT count(*) as recordcount FROM calendar where '" & rs.Fields("TaskDate").Value & "' >= CalendarDate And '" & rs.Fields("TaskDate").Value & "' <= CalendarDate And CalendarWorkDay = 1"
'open recordset
Set rs2 = New ADODB.Recordset
rs2.Open strSQL, objConn2
'Get your answer from the return
heresYourAnswer = rs2.Fields("recordcount").Value
'Iterate to next record in rs
rs.MoveNext
Loop
End Sub
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.