【问题标题】:In Excel VBA run SQL "SELECT ... INTO ... IN ...." Statement在 Excel VBA 中运行 SQL "SELECT ... INTO ... IN ...." 语句
【发布时间】:2018-10-03 13:19:40
【问题描述】:

我似乎找不到任何好的参考或示例来说明如何使其工作。我有一个存储在 AS/400 上的数据库(我的本地 MS Access 数据库 [存储在网络驱动器上] 使用 ODBC/DSN 将表链接到 400)。我的实用程序工作得很好,将 SQL 语句传递给通过 Access 使用链接表从 400 检索数据。问题在于,对于一​​些较大的报告以及 400 位于几个州之外的事实,运行报告可能需要几个小时。解决此问题的解决方案是创建所需表的本地“副本”,其中仅包含与报告相关的数据集,这是一个相当小的数据集。显然,这具有不是“实时”数据的缺点,但我可以忍受。最终我想要做的是从链接表中收集相关数据并将其保存到客户端本地的单独数据库中,以便在离线/离线时可以使用它并提高报告的速度。

网络位置存储数据库 = DB1(表链接到 AS/400) 本地客户端存储数据库=DB2(以下SQL创建的相关数据集,非链接表与链接表同名)

下面是我尝试使用 VBA 和 DAO 工作的 SQL 语句

SELECT 
    DB1_TABLEA.FIELD1, 
    DB1_TABLEA.FIELD2, 
    DB1_TABLEA.FIELD3, 
    DB1_TABLEA.FIELD4, 
    DB1_TABLEA.FIELD5, 
    DB1_TABLEA.FIELD6, 
    DB1_TABLEA.FIELD7, 
    DB1_TABLEA.FIELD8 
INTO 
    DB1_TABLEA IN 'Local_DB_Copy.accdb'    <== Creating non-linked copy 
FROM 
    DB1_TABLEA
WHERE 
    (
        ((DB1_TABLEA.FIELD4) Like 99999) 
        AND 
        ((DB1_TABLEA.FIELD6)="02" Or (DB1_TABLEA.FIELD6)="22")
    )
;

我的程序已经可以正常工作并返回/处理来自 AS/400 DB 的数据。我只需要能够使上述内容正常工作,以便人们可以选择运行处理速度更快的本地副本。

下面是我尝试过的代码,但它当然会失败,否则我不会在这里。

Sub gCreateLocalDBTables()
    Dim DBPath As String
    Dim LocalDBPath As String
    Dim sSQL As String
    Dim DB As DAO.Database
    Dim DB2 As DAO.Database
    Dim RS As DAO.Recordset
        LocalDBPath = "AS400_Local.accdb"
        sSQL = "SELECT DB1_TABLEA.FIELD1, DB1_TABLEA.FIELD2, DB1_TABLEA.FIELD3, DB1_TABLEA.FIELD4, DB1_TABLEA.FIELD5, DB1_TABLEA.FIELD6, DB1_TABLEA.FIELD7, DB1_TABLEA.FIELD8 INTO DB2_TABLEA IN '" & LocalDBPath & "' FROM DB1_TABLEA WHERE (((DB1_TABLEA.FIELD4) Like 99999) AND ((DB1_TABLEA.FIELD6)='02' Or (DB1_TABLEA.FIELD6)='22'));"
        Set DB = OpenDatabase(LocalDBPath, False, False)
        DB.TableDefs.Delete ("DB2_TABLEA")
        DB.Close
        DBPath = Interaction.GetSetting("Cust_Tools", "Settings\Report_Planning", "400DB_Location")
        Set DB2 = OpenDatabase(DBPath, False, False)
        Set RS = DB2.OpenRecordset(sSQL)
        RS.Close
        DB2.Close
        Set RS = Nothing
        Set DB = Nothing
        Set DB2 = Nothing
End Sub

我知道 SQL 可以正常工作,因为我在 MS Access 中对其进行了测试。我只是找不到有关如何从 Excel VBA 传递它的信息

【问题讨论】:

  • 你遇到什么错误?
  • @Kubie - 在线Set RS = DB2.OpenRecordSet (sSQL) 我收到以下错误“运行时错误'3067':查询输入必须包含至少一个表或查询。”
  • 我也尝试将Set RS = DB2.OpenRecordset (sSQL) 更改为DB2.Execute sSQL 并仍然收到相同的错误:/
  • 你考虑过用 ADODB 代替 DAO 吗?我们在这里也大量使用大型机,ADODB 对我来说效果很好。
  • 您的设置不清楚。 我有一个存储在大型机上的数据库 ...这主要是指 IBM 的 DB2。 MS Access 如何适应这一点?您是否已将表链接到 MS Access 中的 DB2。

标签: sql vba excel dao


【解决方案1】:

您不能将像生成表查询(即 SELECTINTO 调用)这样的操作查询分配给记录集。考虑在本地表上打开记录集之前执行您的DROPSELECT ... INTO 操作查询。此外,还不清楚您为什么要打开第二个数据库或路径指向什么。下面打开一个关于大型机数据的记录集:

Set DB = OpenDatabase(LocalDBPath, False, False)

DB.Execute "DROP TABLE DB2_TABLEA", dbFailOnError
DB.Execute sSQL, dbFailOnError

Set RS = DB.OpenRecordset("SELECT * FROM DB2_TABLEA")

此外,生成表查询中的IN 子句是不必要的,因为您当前连接到正在运行操作的数据库。只需将其删除('" & LocalDBPath & "')。此外,LIKE 不带通配符和数字的表达式应替换为 =

SELECT 
    DB1_TABLEA.FIELD1, 
    DB1_TABLEA.FIELD2, 
    DB1_TABLEA.FIELD3, 
    DB1_TABLEA.FIELD4, 
    DB1_TABLEA.FIELD5, 
    DB1_TABLEA.FIELD6, 
    DB1_TABLEA.FIELD7, 
    DB1_TABLEA.FIELD8 
INTO 
    DB2_TABLEA 
FROM 
    DB1_TABLEA
WHERE 
    (
        ((DB1_TABLEA.FIELD4) = 99999) 
        AND 
        ((DB1_TABLEA.FIELD6)='02' OR (DB1_TABLEA.FIELD6)='22')
    )
;

事实上,考虑将查询保存在 MS Access 数据库中(功能区 -> 创建 -> 查询设计 -> SQL 视图)并将其作为命名对象调用,避免在 VBA 中使用任何长 SQL。

DB.Execute "DROP TABLE DB2_TABLEA", dbFailOnError
DB.Execute "mySavedQuery", dbFailOnError

Set RS = DB.OpenRecordset("SELECT * FROM DB2_TABLEA")

【讨论】:

  • 所以在运行此代码之前不存在数据库的本地副本?
  • 如果本地副本存在,将删除其中的表并重新创建以刷新数据。
  • Parfait - 我已将此标记为答案。我意识到我的 SQL 语句中的&amp; DBPath &amp; 应该是&amp; LocalDBPath &amp;。一旦我进行了更改,我的 SQL 就可以使用您建议的 db.Execute 方法完美运行
  • 很高兴听到!乐意效劳。我在 Linux 桌面上使用 DB2。在大型机上运行会很酷!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-10-18
  • 2021-01-19
  • 1970-01-01
  • 2021-12-23
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多