I am trying to run an Access Macro from Excel. I set a reference to Microsoft Office 14.0 Access database engine Object Library. Now, I'm trying to run a small script like this.
Sub RunAccessMacro()
Dim strDatabasePath As String
Dim PathToDB As String
Dim db As DAO.Database
Dim rs As DAO.Recordset
PathOfDatabase = ThisWorkbook.Worksheets("Updates").Range("PathToAccess")
Set db = DAO.DBEngine.OpenDatabase(PathOfDatabase)
Set qry = db.Execute("Macro_Run_Key")
qry.Close
db.Close
MsgBox "Done! All processes complete!!"
End Sub
The problem is, the db.Execute won't execute the Macro. I don't even see anything like RunMacro, or whatever it's called.
There must be a way to do this, right.
The database engine only does database things (anything with tables and queries). If you want more than that, you will have to use the Access application through VBA:
Sub RunAccessMacro()
Dim strDatabasePath As String
Dim PathToDB As String
Dim accApp As Access.Application
Set accApp = New Access.Application
PathOfDatabase = ThisWorkbook.Worksheets("Updates").Range("PathToAccess")
accApp.OpenCurrentDatabase PathOfDatabase
accApp.DoCmd.RunMacro "Macro_Run_Key"
accApp.Quit
Set accApp = Nothing
MsgBox "Done! All processes complete!!"
End Sub
Also, you will need to add a reference to the Microsoft Access Object Library, or you can adapt this code to use late bindings.
Setting a reference to the Access Object Library is useless unless you actually use it :) Seriously, the code written above uses DAO which is a different animal than calling Access directly through the Object Libary. DAO is strictly a database engine (like ADO) and does not know about macros and modules and such as defined in Office Apps.
Here is the code to use when using early binding:
Sub RunAccessMacro()
Dim PathOfDatabase As String
PathOfDatabase = ThisWorkbook.Worksheets("Updates").Range("PathToAccess")
Dim accApp As Access.Application
Set accApp = New Access.Application
With accApp
.OpenCurrentDatabase PathOfDatabase
.DoCmd.RunMacro "Macro_Run_Key"
.Quit
End With
MsgBox "Done! All processes complete!!"
End Sub
If the macro is an Access Macro, you can actually trigger the macro with a single command rather than having to go around the houses. The /X command line switch will help - check this link: How can I schedule a Macro to run automatically in Access 2007
Related
I have a VBA procedure in Word that checks to see if a QueryDef exists in an Access database. It was working fine until a few days ago, when it started crashing Word.
The issue seems to be this line: For Each qdf In db.QueryDefs. This is the line on which Word hangs and then crashes. I don't think it's my code because I have created a very basic test procedure in a new Word document that is just a loop with nothing in it (see below) and created a new Access database and it still crashes.
A connection to the database is successfully made as I get the locked database file. And this code will successfully execute and print to immediate window: Debug.Print db.QueryDefs.Count
I also tested this basic procedure with the empty loop in Excel and it crashes there too. I also updated Office (I'm on Office 365, desktop version of Office). Is there something I'm missing?
Reference to: Microsoft Office 16.0 Access Database Engine Object Library
Option Explicit
Sub Test()
Dim qdf As DAO.QueryDef
Dim db As DAO.Database
Set db = OpenDatabase("DatabasePathAndFileName")
Debug.Print db.QueryDefs.Count
For Each qdf In db.QueryDefs
Next qdf
End Sub
Hit F9 as you step through the code and post back with the exact error. Also, have you restarted the machine recently? I have seen CTRL-Breaks build up over time, and cause all kinds of weirdness, but a restart usually fixes everything. Finally, what changed since it was working last??!!
Try this. What happens?
Public Sub ExecParameterQuery()
Dim dbs As DAO.Database
Dim qdf As DAO.QueryDef
Set dbs = CurrentDb
Set qdf = dbs.QueryDefs("myActionQuery")
'Set the value of the QueryDef's parameter
qdf.Parameters("Organization").Value = "Microsoft"
'Execute the query
qdf.Execute dbFailOnError
'Clean up
qdf.Close
Set qdf = Nothing
Set dbs = Nothing
End Sub
Try stepping through the collection to see if it is a specific query that causes the problem:
Sub Test()
Dim qdf As DAO.QueryDef
Dim db As DAO.Database
Set db = OpenDatabase("DatabasePathAndFileName")
If db.QueryDefs.Count > 0 Then
For Each qdf In db.QueryDefs
MsgBox qdf.Name
Next qdf
End If
End Sub
A client recently upgraded from Windows 7 to 10 and moved from Access 2013 to 2016 (Included with Office 365).
A VBA macro in Excel now generates the following error:
"Run-time error '-2147221164 (80040154)' Class Not Registered." at the line:
Set myEngine = New DAO.DBEngine
I verified that DAO 3.6 is included in Resources. One site suggested "fixing" the Office install, which I did to no effect.
This response suggests moving to ADO, which I might be willing if I could find some examples of how to do so.
Here is the relevant code:
Option Base 1
Sub importPLCDataFromAccess(monthToImport As Date)
'This sub imports Influent and Effluent Data from the Access Database PLC_Data.mdb
' This database reads records from the PLC board on a daily basis and was created
' using Automation Direct's PointOfView software for interfacing with PLC Boards
Dim myDbLocation As String
myDbLocation = "K:\Users\WWTP Computer\Documents\POV_Projects\PLC Interface\PLC_Data.mdb"
Dim myWorkbook As Workbook
'Skip spurious stuff ...
Dim myEngine As DAO.DBEngine
Dim myDB As DAO.Database
Dim myRecordSet As DAO.Recordset
Dim myWorkSpace As DAO.Workspace
'Skip more spurious stuff ...
Set myEngine = New DAO.DBEngine ' This is the offending line
Set myDB = myEngine.OpenDatabase(myDbLocation)
It seems like I am missing something elementary here. Any help is appreciated.
I would recommend using late binding for code portability. As soon as you get this working you'll just find it fails later on a different computer. Declare everything as object and then pull in the references as you need with the CreateObject command.
EXAMPLE:
Public Function GetDBEngine() As Object
On Error Resume Next
'try 120
Set GetDBEngine = CreateObject("DAO.DBEngine.120")
If Err.Number <> 0 Then
'try 36
Err.Clear
Set GetDBEngine = CreateObject("DAO.DBEngine.36")
If Err.Number <> 0 Then
Set GetDBEngine = CreateObject("DAO.DBEngine.35")
Err.Clear
End If
End If
On Error Goto 0
End Function
Sub importPLCDataFromAccess(monthToImport As Date)
'This sub imports Influent and Effluent Data from the Access Database PLC_Data.mdb
' This database reads records from the PLC board on a daily basis and was created
' using Automation Direct's PointOfView software for interfacing with PLC Boards
Dim myDbLocation As String
myDbLocation = "K:\Users\WWTP Computer\Documents\POV_Projects\PLC Interface\PLC_Data.mdb"
Dim myWorkbook As Workbook
'Skip spurious stuff ...
Dim myEngine As Object
Dim myDB As Object
Dim myRecordSet As Object
Dim myWorkSpace As Object
'Skip more spurious stuff ...
Set myEngine = GetDBEngine
Set myDB = myEngine.OpenDatabase(myDbLocation)
FOOTNOTE:
While we are here, can I talk you out of the Option Base 1 ? Surely, there are other ways of making your code start at 1 that don't violate the spacetime continuum.
I just encountered two issues. For one thing, I can't seem to run a Make Table Query in Access, from Excel. I'm getting an error message that says 'Table Risk Rating already exists'. There must be a way to run a Make table Query from Excel. Also, and more importantly, my code seems very unstable. If I run it by hitting F8 over and over, everything works fine. If I run it by a button click event, I get the following error: 'The remote server machine does not exist or is unavailable'. It seems like Excel is losing it's communication with Access. That's just a guess. This thing is on my desktop, so I don't really think this the remote machine is unavailable.
Here is my code.
Sub RunQueriesInAccess()
Dim AC As Access.Application
Set AC = CreateObject("Access.Application")
strDatabasePath = ThisWorkbook.Path & "\Database1.accdb"
With AC
.OpenCurrentDatabase (strDatabasePath)
.CurrentDb.Execute "qry_RISK_RATING"
.CurrentDb.Execute "qry_Delete_ALLL"
Set DB = AC.CurrentDb
Set qry = DB.QueryDefs("qry_DATA_HIST")
qry.Parameters(0) = Worksheets("Impact Analysis New").Range("B1").Value
qry.Execute
Set qry = DB.QueryDefs("qry_LIMIT_HIST")
qry.Parameters(0) = Worksheets("Impact Analysis New").Range("B1").Value
qry.Execute
.Quit
End With
ActiveWorkbook.RefreshAll
End Sub
Any idea what's going on here?
Thanks!!
I'm going to answer what I know, but can't replicate vague instability.
Using .CurrentDb.Execute, you can execute action queries, but can't overwrite tables using a CREATE TABLE or SELECT ... INTO query.
Using .DoCmd.SetWarnings False and .DoCmd.OpenQuery, however, you can.
You can use .DoCmd.SetParameter if your parameterized queries are also creating tables.
You are using a lot of undeclared variables in your piece of code. I'm going to declare them for you and use late binding for the Access.Application, instead of your early/late binding combo thing you got there.
Sub RunQueriesInAccess()
Dim AC As Object
Set AC = CreateObject("Access.Application")
Dim strDatabasePath As String
strDatabasePath = ThisWorkbook.Path & "\Database1.accdb"
With AC
.OpenCurrentDatabase (strDatabasePath)
Dim db As Object
Set db = .CurrentDb
.DoCmd.SetWarnings False
.DoCmd.OpenQuery "qry_RISK_RATING"
.DoCmd.OpenQuery "qry_Delete_ALLL"
Dim qry As Object
Set qry = db.QueryDefs("qry_DATA_HIST")
qry.Parameters(0) = Worksheets("Impact Analysis New").Range("B1").Value
qry.Execute
Set qry = db.QueryDefs("qry_LIMIT_HIST")
qry.Parameters(0) = Worksheets("Impact Analysis New").Range("B1").Value
qry.Execute
.DoCmd.SetWarnings True
.Quit
End With
ActiveWorkbook.RefreshAll
End Sub
I'm trying to run Access DB queries in Excel, but facing problem.
Dim dbs As DAO.Database
Set dbs = CurrentDb
dbs.Execute "DELETE FROM tblMyTable WHERE Bad", dbFailOnError
here it's getting
run time error 424 object required
exactly on the 2ndline
set dbs = CurrentDb
I already added reference DAO 3.6 object library. what to keep in place of CurrentDB. My MsAccess DB is in local disk.
CurrentDb isn't recognized by Excel, so it's being treated as an empty variant, since you haven't assigned it anything. Using Option Explicit will prevent this sort of problem in the future.
If your DB is already open, try something like: Set dbs = GetObject(,"Access.Application").CurrentDb
Option Explicit '### This goes at the VERY TOP of ALL MODULES
Sub foo()
Dim dbs As DAO.Database
Dim appAccess as Object '# Access.Application
Set appAccess = GetObject(,"Access.Application") '# Get a handle on Access
Set dbs = appAccess.CurrentDb
dbs.Execute "DELETE FROM tblMyTable WHERE Bad", dbFailOnError
End Sub
We all know that ms access is not multitreaded so when msacces runs a long query it hangs waiting to the query to be completed. what i want is open from access an new instance of access to run a query or run vba code in background. after running it needs to kit itself after it turns back the results (maybe though the sql server background)
i have seen something before in excel but i wonder if it is posible to do in access
the excel variant is here [excel swarm][1
UPDate
i open access with the folowing code
Dim appAccess As Object
Set appAccess = CreateObject("Access.Application")
Call appAccess.OpenCurrentDatabase( _ "D:\test.accdb")
appAccess.UserControl = True
Set appAccess = Nothing
the target access db is preformatted with a loop as test with is started when access opens. the problem is that the souce access hangs during starting ans running of the target access.
i can use the timer to give it a delayed start and then its working.
the main problem is how can i stat a not preformated access db, create things like vba code, querys odbc connections etc and run it without the source db being hanging.
you could try something like this from a shell command to another VBA host, say excel, which could trigger the event. This is a class, where the properties of DB path and Query name are passed in, then GO is executed, it uses the Execute Complete event of the DBs ADO connection, I've coded it to create an Excel instance and populate with the results.
Ive not tested this fully as in the middle of something, but i'll test fully at lunch and edit as req'd, but a starting point
Option Explicit
Private WithEvents c As ADODB.Connection
Private strDBPath As String
Private strQueryToRun As String
Public Property Let DBPath(strPath As String)
strDBPath = strPath
End Property
Public Property Let QueryToRun(strQuery As String)
strQueryToRun = strQuery
End Property
Public Function GO()
Dim a As New Access.Application
a.OpenCurrentDatabase strDBPath, False
Set c = a.CurrentProject.Connection
c.EXECUTE strQueryToRun
a.CloseCurrentDatabase
a.Quit
Set a = Nothing
End Function
Private Sub c_ExecuteComplete(ByVal RecordsAffected As Long, ByVal pError As ADODB.Error, adStatus As ADODB.EventStatusEnum, _
ByVal pCommand As ADODB.Command, ByVal pRecordset As ADODB.Recordset, ByVal pConnection As ADODB.Connection)
' what to do with the results?
Dim xl As New Excel.Application
Dim xlWb As Excel.Workbook
xl.Visible = True
Set xlWb = xl.Workbooks.Add
xlWb.Sheets(1).Range("a1").CopyFromRecordset pRecordset
End Sub
Yes, that is possible.
Use command Shell to open another instance of Access - and add command line parameters Access to hold info about which queries to run.