Excel 处理AddNew密钥冲突ADODB.Recordset

Excel 处理AddNew密钥冲突ADODB.Recordset,excel,ms-access,vba,ado,Excel,Ms Access,Vba,Ado,我以前的标题引起了一些混乱…更新了 我最近在使用VBA连接Excel和Access时遇到了这个问题 因此,我有一个电子表格,其中包含一个需要导入Access数据库的表。 该表是如下所示的通用表 EmployeeNumber Unused_Field2 Unused_Field3 1 @@@ @@@ 2 @@@ @@@ 3 @@

我以前的标题引起了一些混乱…更新了 我最近在使用VBA连接Excel和Access时遇到了这个问题

因此,我有一个电子表格,其中包含一个需要导入Access数据库的表。 该表是如下所示的通用表

EmployeeNumber  Unused_Field2   Unused_Field3
1                    @@@              @@@
2                    @@@              @@@
3                    @@@              @@@
Access中的唯一密钥设置为EmployeeNumber

Excel中的VBA代码如下所示:

Sub test()
    Dim con As ADODB.Connection
    Dim rst As ADODB.Recordset

    strcon = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=c:\temp\mydb.mdb;"
    strsql = "SELECT * FROM Table1"

    Set con = New Connection
    Set rst = New Recordset

    con.Open strcon
    rst.Open strsql, strcon, adOpenStatic, adLockOptimistic

    For i = 0 To n
        On Error GoTo Errhdl
        rst.AddNew Array("Field1", "Field2", "Field3"), Array(Range("A" & i), Range("B" & i), Range("C" & i))
        On Error GoTo 0
    Next

    Exit Sub

Errhdl:

    Debug.Print "Record" & i & "caused an error"
    Resume Next

End Sub
不幸的是,数据的质量不高,我经常会有重复的值,这会一直导致密钥冲突。 虽然我认为Resume Next将清除允许另一个“AddNew”运行的错误,但它没有。 一次密钥冲突之后的所有后续条目都将返回相同的错误

因此,我的问题如下:

  • 是否有方法清除与记录集相关的错误?(作为记录,我尝试获取“错误集合”并使用 方法Errors.Clear。这不起作用。错误集合是ADO对象特有的属性-)
  • 在不关闭和重新打开记录集的情况下,是否可以执行此操作

  • 请让我知道,如果需要更多的澄清

    我不会使用错误处理(处理ADO错误很棘手),而是在执行插入之前,每次检查密钥是否不存在时使用。如果键是索引字段(如您的说明所示),那么您可能会考虑<代码>查找< /代码>,这对于大型数据集更有效。(但是,
    Seek
    不适用于客户端光标-
    adUseClient

    以下是我发现的一段代码片段,概述了以下步骤:

    If Not .EOF Then
       .MoveFirst
       .Find "TPItemNbr='" & m_TPItemNbr & "'", , adSearchForward
    End If
    If .EOF Then
       .AddNew
       !TPItemVendorID = m_TPItemVendorID
       !TPItemNbr = m_TPItemNbr
       !TPItemEUOM = m_TPItemEUOM
       !TPItemUOMFactor = m_TPItemUOMFactor
       !TPItemPUOM = m_TPItemPUOM
       !TPItemDescription = m_TPItemDescription
       !TPItemUnitCost = m_TPItemUnitCost
       !TPItemUnitLabor = m_TPItemUnitLabor
       .Update
    
    也就是说,每次在循环中执行一次查找,如果EOF(文件结束)为true,则键不在表中,因此可以执行插入

    添加了,以响应有关复合键的更多信息。 我将创建一个
    命令
    对象并使用
    执行
    。是的,它需要创建一个字符串,但您可以捕获并忽略密钥冲突的错误

    替代方案可能是

    • 运行单独的SQL语句以获取重复列表的记录集
    • 循环执行此操作,并将值存储在数组中
    • 每次检查阵列时执行
      AddNew
    这对我来说似乎很混乱,特别是在搜索数组方面

    • 采用注释中链接的多重查找方法

    因此,如果Recordset.AddNew遇到错误,我找到了解决方案。 诀窍是使用CancelUpdate-

    还可以使用Status属性检查操作是否成功

    示例代码为:

    Sub test()
        Dim con As ADODB.Connection
        Dim rst As ADODB.Recordset
    
        strcon = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=c:\temp\mydb.mdb;"
        strsql = "SELECT * FROM Table1"
    
        Set con = New Connection
        Set rst = New Recordset
    
        con.Open strcon
        rst.Open strsql, strcon, adOpenStatic, adLockOptimistic
    
        For i = 0 To n
            On Error GoTo Errhdl
            rst.AddNew Array("Field1", "Field2", "Field3"), Array(Range("A" & i), Range("B" & i), Range("C" & i))
            On Error GoTo 0
        Next
    
        Exit Sub
    
    Errhdl:
    
        Debug.Print "Record" & i & "caused an error"
        If rst.Status <> 0 Then
            rst.CancelUpdate
        End If
        Resume Next
    
    End Sub
    
    子测试()
    Dim con作为ADODB连接
    将rst设置为ADODB.Recordset
    strcon=“Provider=Microsoft.Jet.OLEDB.4.0;数据源=c:\temp\mydb.mdb;”
    strsql=“从表1中选择*”
    Set con=新连接
    Set rst=新记录集
    con.开放式strcon
    rst.打开strsql、strcon、adOpenStatic、ADLOCK
    对于i=0到n
    关于错误转到Errhdl
    rst.AddNew数组(“字段1”、“字段2”、“字段3”)、数组(范围(“A”和i)、范围(“B”和i)、范围(“C”和i))
    错误转到0
    下一个
    出口接头
    Errhdl:
    调试。打印“记录”&i&“导致错误”
    如果rst.Status为0,则
    rst.CancelUpdate
    如果结束
    下一步继续
    端接头
    
    我会首先将您的标签重命名为除
    Err
    之外的其他名称,这已经是VBA中的一个对象。您不能使用
    命令
    而不是
    记录集
    来执行
    插入
    s吗?@shahkalpesh是的,Command.execute方法将与resumenext一起工作,但是与记录集相比,它提供的控制更少。另外,这意味着我需要一个字符串构造函数来构造SQL语句,它有时很容易出错,特别是对于不同的数据类型和特殊字符。(这是我的观点)@DerekCheng:不,我认为它不容易出错<代码>命令与
    参数
    集合一起使用是一种简单、无错误的方法,无需进行字符串连接。就是一个例子。+1是的,参数(一如既往)减轻了构造sql的痛苦。就个人而言,我不会使用Array()方法,我只会设置单个字段。IMO使用数组增加了一些复杂性,并且更容易出错。但这只是我的意见;)首先谢谢你的回答。我考虑过在添加新的之前做一次搜索。但是在性能方面,如果我的表大小由许多行组成,它会使过程慢很多吗?另外,如果表有一个复合键(我知道我们不应该使用复合键…但这不取决于我…),那么.Find将不起作用(如果我在这里出错,请纠正我)我将不得不使用微软建议的多频函数-