Ms access 错误转到不工作;代码中断
我正在编写一个VBA函数,以便在Access中将数据从一个表导入另一个表。我要导入的表具有更严格的数据约束(即类型、大小等),因此我预计会有很多错误 我希望我的记录集循环跳过整个当前记录,并在遇到错误时将其记录在单独的表中,而不是筛选出现的每个VBA错误。所以我每隔插入一行Ms access 错误转到不工作;代码中断,ms-access,error-handling,vba,Ms Access,Error Handling,Vba,我正在编写一个VBA函数,以便在Access中将数据从一个表导入另一个表。我要导入的表具有更严格的数据约束(即类型、大小等),因此我预计会有很多错误 我希望我的记录集循环跳过整个当前记录,并在遇到错误时将其记录在单独的表中,而不是筛选出现的每个VBA错误。所以我每隔插入一行就转到RecordError。但由于某些原因,它并没有处理每一个错误。我的代码只是中断并告诉我错误是什么。我已经选中了“中断未处理的异常”选项 这里有一个屏幕截图可以解释这一点。 为什么它会在错误处理程序之后立即断线?您需要
就转到RecordError
。但由于某些原因,它并没有处理每一个错误。我的代码只是中断并告诉我错误是什么。我已经选中了“中断未处理的异常”选项
这里有一个屏幕截图可以解释这一点。
为什么它会在错误处理程序之后立即断线?您需要将
放在错误
行中,然后再放在希望处理其错误的代码之前
更重要的是,您只需要在错误行上有一个
。然后,错误处理程序将保持活动状态,直到子例程退出或您执行另一条关于错误的语句。我认为您不了解VB(A)错误处理的工作原理。遵循以下原则:
On Error…
语句仅适用于它出现的例程(子例程或函数)(尽管它也会捕获从使用它的例程中调用的例程中“冒泡”的错误)
On Error
设置状态。也就是说,一旦您发出一个On Error…
,它将在例程的其余部分保持有效,除非被一个新的On Error…
取代
- 错误时有四种形式的
。
:
在错误转到时
:
必须在同一例程中定义,方法是在标签名称后面紧跟一个冒号(:)并单独在一行上写入
错误恢复时
:立即重试错误抛出语句。很少使用,因为它可能是无限的
错误恢复下一步
:忽略错误并继续。有时在清理例程结束时很有用(例如,如果要关闭可能打开或可能未打开的记录集)。或者,如果在任何可能引发错误的行之后立即检查Err
对象,也可以使用此表单(如果Err.Number
为零(0),则语句成功而不引发错误)。在大多数情况下,这是太多的工作了
关于错误转到0
:关闭错误处理
有鉴于此,通常会在例程声明(Sub
或函数
语句)之后立即将置于Error…
语句上,尽管有些人会将Dim
语句放在两者之间。如果要临时更改例程中的错误处理方式,请将“新”放在要应用它的代码之前,并(如果使用)将“还原”(重新发布原始)放在代码之后
即使考虑到所有这些,我也不知道为什么当选择“break on Unhandled Errors”(在未处理的错误上中断)时,它会在错误抛出行中断,除非您将它弄得非常混乱,以至于它认为没有活动的错误处理(如果是这样的话,我会感到惊讶)
请注意,David Heffernan在其回答中向您介绍了这一问题的基本部分,而这一部分在我之前就已经存在了。使用VBA处理错误是一个真正的难题。我建议你看一看,并根据自己的情况进行调整。您可以轻松地编写一些代码,将所有错误消息存储在一个表中,从而构建一个事实上的错误报告系统。没有人真正回答您的问题
假设您的代码是这样的(框架):
在这段代码中,您在错误处理程序中使用SELECT案例来决定要忽略哪些错误。在上面的代码框架中,我将错误号列为X,Y,Z
,但您可以将其替换为要忽略的实际错误号
您不希望忽略每个错误,因为您可能最终会忽略子例程中其他地方的重要错误。如果你不想知道你想要忽略的有限数量的错误是什么,我建议你在产生你想要忽略的错误的代码块的开头设置一个标志,然后使用'If-bolErrorInCodeBlockToIgnore'来决定你是否忽略了所有的错误。大概是这样的:
Public Sub MySub()
On Error GoTo errHandler
Dim rs As DAO.Recordset
Dim bolErrorInCodeBlockToIgnore As Boolean
Set rs = CurrentDB.OpenRecords([SQL SELECT])
If rs.RecordCount >0 Then
rs.MoveFirst
Do Until rs.EOF
bolErrorInCodeBlockToIgnore = True
[do whatever that produces the error]
errSkipToNext:
rs.MoveNext
Loop
End If
exitRoutine:
If Not (rs Is Nothing) Then
rs.Close
Set rs = Nothing
Exit Sub
errHandler:
If bolErrorInCodeBlockToIgnore Then
Err.Clear
' do whatever it is you need to do in order to record the offending row
Call RecordError(rs!PK, Err.Number) ' PK is a field that identifies the bad record
bolErrorInCodeBlockToIgnore = False
GoTo errSkipToNext
Else
MsgBox Err.Number & ": " & Err.Description, vbExclamation, _
"Error!"
Resume exitRoutine
End If
End Sub
我更喜欢第一种,因为我坚信只忽略已知的错误,而不忽略发生的任何旧错误。但是,要设计出能够产生所有可能的错误的测试可能会非常困难。它不起作用的原因是因为您无法使用On Error Goto。。。在错误处理程序中
看
您不能使用On Error跳过几行,相反,On Error应该转到一个错误处理程序,然后继续到所需的下一行(在您的示例中,您可能会得到一个错误处理程序,其中包含一个resume next,它将带您返回下一个字段)
感谢Tim Williams提出的这个问题:
顺便说一句,ZIP上的ParseInt将破坏以0开头的邮政编码,zipcodes可能应被视为文本。我也看到错误处理失败。这里有一个例子
Public Function Have(ByVal item As Variant) As Boolean
'Have = Have data. Simplifies handling nulls and empty strings in validation code
On Error GoTo Procerr
If IsNull(item) Then
Have = False
**ElseIf Len(Trim(item)) = 0 Then 'Faster than Item <> ""**
Have = False
ElseIf item = 0 Then
Have = False
Else
Have = True
End If
exitproc:
Exit Function
Procerr:
'Errors sometimes occur if an unbound control is referenced
Have = False
End Function
公共函数将(ByVal项作为变量)设置为布尔值
'Have=有数据。简化了验证代码中空字符串和空字符串的处理
关于错误转到Procerr
如果为空(项目),则
Have=False
**ElseIf Len(修剪(项目))=0然后“比项目快”**
Have=False
ElseIf item=0则
Have=False
其他的
Have=True
如果结束
出口程序:
退出功能
Procerr:
'如果引用未绑定的控件,有时会发生错误
Have=False
端函数
该代码有时在运行时失败
Public Function Have(ByVal item As Variant) As Boolean
'Have = Have data. Simplifies handling nulls and empty strings in validation code
On Error GoTo Procerr
If IsNull(item) Then
Have = False
**ElseIf Len(Trim(item)) = 0 Then 'Faster than Item <> ""**
Have = False
ElseIf item = 0 Then
Have = False
Else
Have = True
End If
exitproc:
Exit Function
Procerr:
'Errors sometimes occur if an unbound control is referenced
Have = False
End Function