Excel 处理AddNew密钥冲突ADODB.Recordset
我以前的标题引起了一些混乱…更新了 我最近在使用VBA连接Excel和Access时遇到了这个问题 因此,我有一个电子表格,其中包含一个需要导入Access数据库的表。 该表是如下所示的通用表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 @@
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”运行的错误,但它没有。
一次密钥冲突之后的所有后续条目都将返回相同的错误
因此,我的问题如下:
请让我知道,如果需要更多的澄清 我不会使用错误处理(处理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
- 采用注释中链接的多重查找方法
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将不起作用(如果我在这里出错,请纠正我)我将不得不使用微软建议的多频函数-