【问题标题】:VBA Wait for DoCmd.RunSQL OR Better Query - Ms AccessVBA 等待 DoCmd.RunSQL 或更好的查询 - Ms Access
【发布时间】:2012-06-07 13:26:35
【问题描述】:

我有一个查询,它使用表数组(存储为字符串数组)循环遍历我的表并执行删除/更新查询集。除了表名之外,查询是相同的,因此使用循环来迭代使用表名作为变量。

问题是,我的删除查询锁定了表,之后更新查询运行得太快了;我收到“数据库已锁定”错误。

我需要两件事之一:

  1. 一种告诉 VBA“等待上一个命令”或
  2. 的方法
  3. 一种将这些查询连接成一个(或两个)查询的方法:一个用于删除数据库行,另一个用于导入新行。有了这个,我可以从标准访问查询中运行查询(应该分配适当的时间,完成查询等)

唯一的问题是存在父子关系,因此父表必须在其子表之前更新(目前通过数组排序完成)。

这是(有时)产生“数据库锁定/正在使用”消息的当前代码:

For i = 0 To UBound(tables)
    'Delete all data first
    sql = "DELETE * FROM " & tables(i)
    DoCmd.RunSQL sql
    'Update all data second
    sql = "INSERT INTO " & tables(i) & " IN """ & toDB & """ SELECT " & tables(i) & " .* FROM " & tables(i) & " IN """ & fromDB & """;"
    DoCmd.RunSQL sql
Next

应该澄清:查询从相同的表中获取一个后端的 (fromDB) 行并将其推送到另一个后端的 (toDB) 行

编辑:在回答有关INSERT INTO 的问题时,我的问题是如果我将字段添加到toDB,如果我覆盖,它将删除它们。我必须使用这种后门方法的原因是因为数据库仍在开发中,但也与选择表一起使用。每天都会进行更新和功能改进。我也不能使用简单的拆分后端,因为访问数据库的另一台计算机并不总是在网络上(当它返回网络时我们必须手动同步它),所以我在一个后端工作,它在另一个后端工作,相同(ish,减去我的架构更新)后端。

【问题讨论】:

  • 您应该使用CurrentDb.Execute sSQL, dbFailOnError 而不是DoCmd.RunSQL
  • 有效,我认为这是更好的做法,但我仍然遇到同样的错误。也许我必须添加一个“等到__未锁定”之类的语句?

标签: sql ms-access vba


【解决方案1】:

您可以使用 ADO 而不是 DoCmd.RunSQL 来同步执行您的 SQL。

 Dim cmd As ADODB.Command
 Dim cnn As New ADODB.Connection

 Set cnn = CurrentProject.Connection

 For i = 0 To UBound(tables)
     Set cmd = New ADODB.Command
     With cmd

        .CommandType = adCmdText
         .ActiveConnection = cnn
        .CommandText = "DELETE * FROM " & tables(i)
        .Execute
      End With

     Set cmd = New ADODB.Command
     With cmd

        .CommandType = adCmdText
         .ActiveConnection = cnn
        .CommandText = "INSERT INTO " & tables(i) & " IN """ & toDB & """ SELECT " & tables(i) & " .* FROM " & tables(i) & " IN """ & fromDB & """;"
        .Execute
      End With

Next

您还可以添加cnn.BeginTranscnn.CommitTrans 以使这两个语句具有原子性。

【讨论】:

  • 可能是一个新手问题,但 VBA 无法识别 ADODB 对象。我需要在某个地方设置一些东西来允许这个对象吗?
  • 您需要使用工具->引用添加对“Microsoft ActiveX 数据对象”的引用。但是,您可以考虑按照 HK1 的评论尝试 CurrentDb.Execute
  • 错误:基本上说你上面的cnn不是一个有效的OLE DB会话对象。
  • 对不起,检查我的编辑应该是Set cnn = CurrentProject.Connection
  • 我想就是这样。您的编辑可能有问题,但给出的错误不是问题(我的最后评论)。我认为这与引用有关,因为代码生成器没有将 ADODB 识别为命令;自动完成上下文菜单没有出现。我添加了引用,重新启动 Access,它找到了 .Command、.CommandType 等。尝试了您的编辑,现在一切正常;无法使用这种方法复制我原来的错误。看起来不错!
【解决方案2】:

尝试这样的事情(注意我已经评论了你的DoCmd.RunSQL。我用db.Execute改变了它:

Sub DeleteInsertData(tables() As String, toDB As String, fromDB As String)

    Dim db As DAO.Database
    Dim i As Integer
    Dim SQL As String
    
    Set db = CurrentDb()
    For i = 0 To UBound(tables)
        'Delete all data first
        SQL = "DELETE * FROM " & tables(i)
        db.Execute SQL, dbFailOnError
        'DoCmd.RunSQL SQL
        'Update all data second
        SQL = "INSERT INTO " & tables(i) & " IN """ & toDB & """ SELECT " & tables(i) & " .* FROM " & tables(i) & " IN """ & fromDB & """;"
        db.Execute SQL, dbFailOnError
        'DoCmd.RunSQL SQL
    Next
    Set db = Nothing
End Sub

【讨论】:

  • DAO 比 ADO 快 ;-)
【解决方案3】:

我不是专家,但我认为您不需要 DELETE 部分。 SELECT INTO 是制作表格的语法。如果表已存在,则将其覆盖。

【讨论】:

    【解决方案4】:

    如果我需要等待某事,我倾向于使用DoEvents 来允许 Windows 处理已暂停的任何其他操作。
    来自帮助:“产生执行,以便操作系统可以处理其他事件。”

    找到这个:
    .BeginTrans然后
    .CommitTrans dbForceOSFlush
    作为在继续之前强制写入更新的一种方式

    【讨论】:

    • 即使使用 DoEvents 也会出现同样的错误。后端被锁定的时间比必要的时间稍长,是否有原因?当然,有了这里建议的所有更改,查询就可以完全运行。为什么后端一直处于锁定状态?
    • 似乎需要刷新缓冲区 - 我将信息添加到我的答案中
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-05-08
    • 1970-01-01
    • 2023-04-03
    • 2010-12-01
    • 1970-01-01
    • 2018-06-14
    • 1970-01-01
    相关资源
    最近更新 更多