Ms access 错误转到不工作;代码中断

Ms access 错误转到不工作;代码中断,ms-access,error-handling,vba,Ms Access,Error Handling,Vba,我正在编写一个VBA函数,以便在Access中将数据从一个表导入另一个表。我要导入的表具有更严格的数据约束(即类型、大小等),因此我预计会有很多错误 我希望我的记录集循环跳过整个当前记录,并在遇到错误时将其记录在单独的表中,而不是筛选出现的每个VBA错误。所以我每隔插入一行就转到RecordError。但由于某些原因,它并没有处理每一个错误。我的代码只是中断并告诉我错误是什么。我已经选中了“中断未处理的异常”选项 这里有一个屏幕截图可以解释这一点。 为什么它会在错误处理程序之后立即断线?您需要

我正在编写一个VBA函数,以便在Access中将数据从一个表导入另一个表。我要导入的表具有更严格的数据约束(即类型、大小等),因此我预计会有很多错误

我希望我的记录集循环跳过整个当前记录,并在遇到错误时将其记录在单独的表中,而不是筛选出现的每个VBA错误。所以我每隔插入一行
就转到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