简体   繁体   English

从Excel VBA运行访问查询

[英]Run Access Queries from Excel VBA

I am trying to write a macro in excel vba that simply opens an access database and runs 2 queries in access. 我正在尝试在excel vba中编写一个宏,该宏仅打开一个访问数据库并在访问中运行2个查询。 It seems to work and run the queries every 2 clicks of the macro button. 似乎每两单击一次宏按钮即可运行并运行查询。 What I mean is I click it, it works, the 2nd click I get a 'runtime error 462' on the second click, the third click it works, the fourth click I get the error again and so on. 我的意思是,我单击它,它起作用了,第二次单击时我在第二次单击中得到了“运行时错误462”,第三次单击了,第四次单击又得到了错误,依此类推。 I can't seem to figure out why this is. 我似乎无法弄清楚为什么会这样。 Here is the code below. 这是下面的代码。

Sub QueryAccess1()

Dim db As Access.Application
Set db = New Access.Application
'set variables

db.Visible = True

db.OpenCurrentDatabase ("DatabaseFileName")
'open database

'--------------------------------------------------------------
On Error Resume Next

db.DoCmd.DeleteObject acTable, "TableName"
'if the table does not exist it skips this line
'--------------------------------------------------------------

On Error GoTo 0
'sets the error back to normal

'--------------------------------------------------------------
CurrentDb.Openrecordset ("QUERY1")
CurrentDb.Execute ("QUERY2")
'Calls the queries
'--------------------------------------------------------------

'--------------------------------------------------------------
db.CloseCurrentDatabase
db.Quit
'Closes Access
'--------------------------------------------------------------

Set db = Nothing

End Sub

When I get the error I am getting it on the line 当我得到错误时,我就得到它了

CurrentDb.Openrecordset ("QUERY1")

Likely the every two click error is due to opening the table that was just deleted where every other time it exists. 每两次单击错误可能是由于打开存在于其他位置的刚刚删除的表所致。 Consider iterating through MS Access's TableDefs collection to conditionally delete the object if it exists. 考虑通过MS Access的TableDefs集合进行迭代,以有条件地删除该对象(如果存在)。 Then, re-order your action query to run before OpenRecordset call. 然后,对操作查询重新排序,使其在OpenRecordset调用之前运行。

Public Sub RunQueries()
On Error Goto ErrHandle:
    ' DAO REQUIRES REFERENCE TO Microsoft Office X.X Access Database Engine Object Library
    Dim tbl As DAO.TableDef     
    Dim rs As DAO.Recordset
    Dim db As New Access.Application

    db.Visible = False                   ' KEEP DATABASE RUNNING IN BACKGROUND

    For Each tbl in db.CurrentDb.TableDefs
        If tbl.Name = "TableName" Then
            db.DoCmd.DeleteObject acTable, "TableName"
        End If
    Next tbl

    ' ASSUMED AN ACTION QUERY
    db.CurrentDb.Execute "QUERY2", dbFailOnError

    ' ASSUMED A SELECT QUERY BUT CALL BELOW IS REDUNDANT AS IT IS NEVER USED
    Set rs = db.CurrentDb.OpenRecordset("QUERY1")   

ExitHandle:
    ' FREE RESOURCES
    Set rst = Nothing: Set conn = Nothing
    db.CloseCurrentDatabase
    db.Quit
    Set db = Nothing
    Exit Sub

ErrHandle:
    MsgBox Err.Number & " - " & Err.Description, vbCritical, "RUNTIME ERROR"
    Resume ExitHandle
End Sub

Aside - Avoid ever using On Error Resume Next in VBA. 另外-避免在VBA中使用On Error Resume Next Always proactively anticipate and handle exceptions. 始终主动预测和处理异常。


Alternatively, instead of using the make-table command SELECT * INTO and then having to worry about deleting the table programmatically, simple create your table once and then use DELETE and INSERT which can be run each time. 或者,不必使用make-table命令SELECT * INTO而不必担心以编程方式删除表,只需创建一次表,然后使用可以每次运行的DELETEINSERT Of course this assumes the table's structure (fields/types) remain the same. 当然,这假设表的结构(字段/类型)保持不变。

DELETE FROM myTable;

INSERT INTO myTable (Col1, Col2, Col3) 
SELECT Col1, Col2, Col3 FROM myOtherTable;

SELECT * FROM myTable;

Finally, there is no reason to even use the MS Access object library to open/close the .GUI just to run queries. 最后,甚至没有理由甚至使用MS Access对象库来打开/关闭.GUI只是为了运行查询。 Since Access is a database, connect to it like any other backend (ie, SQLite, Postgres, Oracle) and run your queries from there. 由于Access是一个数据库,因此可以像其他任何后端(即SQLite,Postgres,Oracle)一样连接到该数据库并从那里运行查询。 Below is an ODBC connection example which the driver can easily be swapped for drivers of other RBDMS's. 下面是一个ODBC连接示例,该驱动程序可以轻松替换为其他RBDMS的驱动程序。

Dim conn As Object, rst As Object

Set conn = CreateObject("ADODB.Connection")
Set rst = CreateObject("ADODB.Recordset")

' OPEN CONNECTION
conn.Open "DRIVER={Microsoft Access Driver (*.mdb, *.accdb)};" _
            & "DBQ=C:\Path\To\Access\DB.accdb;"

' RUN ACTION QUERIES
conn.Execute "DELETE FROM myTable"
conn.Execute "INSERT INTO myTable (Col1, Col2, Col3)" _
               & " SELECT Col1, Col2, Col3 FROM myOtherTable"

' OPEN RECORDSET
rst.Open "SELECT * FROM myQuery", conn

' OUTPUT TO WORKSHEET
Worksheets("DATA").Range("A1").CopyFromRecordset rst
rst.Close

In fact, the above approach does not even require MS Access GUI .exe installed! 实际上,以上方法甚至不需要安装MS Access GUI .exe! Also, be sure to save the SELECT query (even one inside INSERT ) inside Access and not run as a VBA SQL string since the Access engine will save the best execution plan for stored queries. 另外,请确保将SELECT查询(甚至在INSERT一个)保存在Access中,并且不要作为VBA SQL字符串运行,因为Access引擎将为存储的查询保存最佳执行计划。

I managed to get it to work with Parfait's method. 我设法使其与Parfait的方法一起使用。 Here is what I have got. 这就是我所得到的。

Sub QueryAccess1()

Dim conn As Object, rst As Object
Dim path As String


Set conn = CreateObject("ADODB.Connection")
Set rst = CreateObject("ADODB.Recordset")

path = Sheets("SheetName").Range("A1")

'OPEN CONNECTION
conn.Open ConnectionString:="Provider = Microsoft.ACE.OLEDB.12.0; data source=" & path

'DELETES TABLE CONTENTS
conn.Execute "DELETE FROM [Table1]"

'RUN UNION QUERY AND INSERT INTO TABLE
rst.Open "SELECT * FROM [Query1]", conn
conn.Execute "INSERT INTO [Table1]  select * from [QUERY1] "

Set rst = Nothing: Set conn = Nothing

End Sub

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM