从 Excel VBA 运行访问查询
Posted
技术标签:
【中文标题】从 Excel VBA 运行访问查询【英文标题】:Run Access Queries from Excel VBA 【发布时间】:2018-05-16 15:22:18 【问题描述】:我正在尝试在 excel vba 中编写一个宏,它只是打开一个 access 数据库并在 access 中运行 2 个查询。它似乎每单击 2 次宏按钮就可以工作并运行查询。我的意思是我点击它,它可以工作,第二次点击我在第二次点击时得到一个“运行时错误 462”,第三次点击它可以工作,第四次点击我再次得到错误,依此类推。我似乎无法弄清楚这是为什么。这是下面的代码。
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
当我收到错误消息时,我将其上线
CurrentDb.Openrecordset ("QUERY1")
【问题讨论】:
尝试使用 OpenQuery,而不是 Openrecordset。如果这不起作用,您可以在编辑模式下打开查询,查看 SQL 视图并在 VBA Excel 上构建/使用 SQL。 Query2 是否创建表“TableName”?也许这就是奇数失败的逻辑? 是的 Query2 确实创建了“TableName”,但我不确定这是否有问题,因为如果表存在,我会先删除它? 哪一行给出了错误? 我在 'CurrentDb.Openrecordset ("QUERY1")' 行得到错误 【参考方案1】:我设法让它与 Parfait 的方法一起使用。这是我得到的。
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
【讨论】:
通常,发布的解决方案永远不会完全符合您的需要。 OP 通常需要进行调整。这里唯一真正的区别是使用 OLEDB 提供程序而不是 ODBC 驱动程序。最后,在这段代码中,您从未使用过 rst,因此删除其set
和 .Open
行并运行操作查询。【参考方案2】:
可能每两次单击错误是由于打开刚刚删除的表,而它每隔一段时间就存在一次。考虑遍历 MS Access 的 TableDefs 集合,以有条件地删除对象(如果存在)。然后,重新排序您的操作查询以在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
除此之外 - 避免在 VBA 中使用 On Error Resume Next
。始终主动预测和处理异常情况。
或者,不用使用 make-table 命令 SELECT * INTO
然后不必担心以编程方式删除表,只需创建表一次,然后使用 DELETE
和 INSERT
每次都可以运行。当然,这假设表的结构(字段/类型)保持不变。
DELETE FROM myTable;
INSERT INTO myTable (Col1, Col2, Col3)
SELECT Col1, Col2, Col3 FROM myOtherTable;
SELECT * FROM myTable;
最后,甚至没有理由使用 MS Access 对象库来打开/关闭 .GUI 来运行查询。由于 Access 是一个数据库,因此像任何其他后端(即 SQLite、Postgres、Oracle)一样连接到它并从那里运行您的查询。下面是一个 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
其实上面的方法甚至不需要安装MS Access GUI .exe!此外,请务必将 SELECT
查询(甚至在 INSERT
中的一个)保存在 Access 中,并且不要作为 VBA SQL 字符串运行,因为 Access 引擎将为存储的查询保存最佳执行计划。
【讨论】:
嗨 Parfait,我想我需要打开 Access Gui 并运行查询,因为第二个查询在 access 中创建了一个表,所以我想关闭访问,因此文件现在与新表一起保存或者我可以在不打开 Access 的情况下执行此操作吗?我还尝试删除“on error resume next”行并添加到循环中以查找表是否存在。这确实有效,但令人沮丧的是,我在第二次运行代码并遇到相同的运行时错误时遇到了同样的问题:( 我应该提到我第二次在 db.Visible = True 运行代码时出错CREATE TABLE
...SELECT * INTO
是 SQL - DDL 命令,因此您不需要 GUI .exe。 MS Access 是一个独特的软件,既是后端又是前端。只有在处理表单/报告/宏/模块等前端应用程序项目时,您才需要 GUI。
按照建议使用正确的错误处理查看编辑,切勿使用On Error Resume Next
。然后,检查弹出的错误消息以正确查看要处理的问题。以上是关于从 Excel VBA 运行访问查询的主要内容,如果未能解决你的问题,请参考以下文章
直接和通过 VBA excel 运行相同的存储 Access SQL 查询时获得不同的结果
如何从访问数据库中的左连接中选择excel表 - EXCEL VBA