错误GoTo不工作;代码中断

时间:2011-04-28 16:41:53

标签: ms-access vba error-handling access-vba

我正在编写一个VBA函数,用于将数据从一个表导入到Access中的另一个表。我导入的表有更严格的数据约束(即类型,大小等),所以我期待很多错误。

我希望我的记录集循环跳过整个当前记录,并在遇到错误时在单独的表中记录它,而不是筛选出现的每个VBA错误。所以我插入的每一行都On Error GoTo RecordError。但由于某种原因,它并没有处理每一个错误。我的代码只是打破并告诉我错误是什么。我已经选中了“打破未处理的例外”选项。

这是一个应该解释它的截图。 Even by itself, this screenshot seems to make no sense to me.

为什么它会在错误处理程序之后立即中断?

7 个答案:

答案 0 :(得分:3)

我认为您不了解VB(A)错误处理的工作原理。遵循以下原则:

  • On Error...语句仅适用于它出现的例程(Sub或Function)(尽管它也会捕获从您使用它的例程中调用的例程中“冒泡”的错误)。
  • On Error设置状态。也就是说,一旦你发出On Error...,它就会对其余例程保持有效,除非被新On Error...取代。
  • On Error...有四种形式:

    1. On Error GoTo <label><label>必须在同一个例程中定义,方法是在一行上单独写一个标签名称后跟冒号(:)。
    2. On Error Resume:立即重试错误抛出语句。几乎没用过,因为它可能是无限的。
    3. On Error Resume Next:忽略错误&amp;继续。有时在例程结束时用于清理(例如,如果要关闭可能打开或未打开的Recordset)。或者,如果在任何可能出错的行(如果Err为零(0))之后立即检查Err.Number对象 ,则也可以使用此表单,该语句成功抛出错误)。对于大多数情况,这是方式太多工作。
    4. On Error GoTo 0:关闭错误处理。

鉴于此,通常将On Error...语句紧跟在例程的声明(SubFunction语句)之后,尽管有些人将Dim语句放入之间。如果要暂时更改例程中的错误处理方式,请将“new”放在要应用的代码之前,并且(如果使用的话),“revert”(重新发布原始版本),紧接着

即使考虑到所有这些,我也不知道为什么当选择“Break on Unhandled Errors”时它会在错误抛出线上中断,除非你设法把它混淆得太多以至于它认为没有主动错误处理(如果是这样的话,我会感到惊讶。)

请注意,David Heffernan在他的回答中给了你最重要的部分,它就在我的面前......

答案 1 :(得分:2)

它无法正常工作的原因是因为您无法在错误处理程序中使用On Error Goto ....

请参阅http://www.cpearson.com/excel/errorhandling.htm

你不能使用On Error来跳过几行,而是在错误时应该转到一个错误处理程序然后恢复到所需的下一行(在你的例子中你可能会得到一个包含一个简历的错误处理程序会带你回到下一个领域。)

感谢蒂姆·威廉姆斯在这个问题:The second of 2 'On Error goto ' statements gets ignored

ZIP上的

和BTW ParseInt将破坏以0开头的邮政编码,邮政编码应该被视为文本。

答案 2 :(得分:1)

您需要将On Error行放在您希望处理其错误的代码之前。

您还需要拥有一条On Error行。然后,错误处理程序将保持活动状态,直到子例程退出或执行另一个On Error语句。

答案 3 :(得分:1)

使用VBA处理错误是一个真正的PITA。我建议你看一下this answer to the 'MS-Access, VBA and error handling' question,让它适应你自己的情况。您可以轻松地写下一些代码,将所有错误消息存储在一个表中,构建一个事实上的错误报告系统。

答案 4 :(得分:1)

将调试模式设置为“中断所有错误”将使程序执行在导致错误的行停止,即使错误处理程序已正确写入也是如此。这可能会让人感到困惑,因为错误处理似乎无法正常工作。

答案 5 :(得分:0)

没有人真的回答过你的问题。

说你的代码是这样的(骨架框架):

Public Sub MySub()
On Error GoTo errHandler
  Dim rs As DAO.Recordset

  Set rs = CurrentDB.OpenRecords([SQL SELECT])
  If rs.RecordCount >0 Then
     rs.MoveFirst
     Do Until rs.EOF
       [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:
  Select Case Err.Number
    Case X, Y, Z ' where these are error numbers you want to ignore
      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
      GoTo errSkipToNext
    Case Else
      MsgBox Err.Number & ": " & Err.Description, vbExclamation, _
         "Error!"
      Resume exitRoutine
  End Select
End Sub

在此代码中,您在错误处理程序中使用SELECT CASE来确定要忽略的错误。在上面的代码框架中,我将错误编号列为X, Y, Z,但您要将其替换为您要忽略的实际错误编号。

您不希望忽略每个错误,因为您最终可能会忽略子例程中其他位置的重要错误。如果你不想弄清楚你想要忽略的有限数量的错误是什么,我建议你在代码块的开头设置一个标志,产生你想要忽略的错误,然后使用`如果是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

我更喜欢第一个,因为我坚信仅忽略已知错误,而不是发生任何旧错误。但是,提出可能产生您想忽略的所有可能错误的测试可能非常困难。

答案 6 :(得分:0)

我也看到错误处理失败了。这是一个例子。

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

代码有时会在标有**的行上失败。这是错误消息。

error dialog

请注意错误处理程序失败。在这种情况下,调用返回代码的表单将其记录源动态设置为空记录集,因此屏幕上的字段不可见。表单是一个连续的表单,因此当表单加载空记录集时,记录和字段不可见。 has()函数不是由我的代码直接调用的,但似乎是由me.requery方法触发的。 has()在我的代码中被调用了数亿次,但这是唯一导致它失败并且错误处理程序没有被驱散的实例。

Lance Roberts重新提出原始问题。 utf-8 unicode有时会对ms访问造成严重破坏,因为它似乎允许数据与指令代码混淆(我猜)。如果最初从文本文件加载数据,utf-8可以进入您的数据。具有字节顺序标记(BoM)的utf-8特别令人讨厌。当您运行一些与数据一起使用的过程时,可能会发生奇怪的错误,并且可能看起来您的文件已损坏。在其他情况下,文本处理功能给出了错误的答案,例如Mid()将看到BOM,如果指定起点将从BOM开始,但Len()忽略BOM。我推测如果你有这个问题,那么ms-access可能无法正确处理错误。我有导入数据和导入utf-8的类似问题,因为ANSI是原因。请注意,对于普通英语数据,utf-8和ANSI在大多数情况下是相同的,因此您的错误可能不会出现在每一行上。我的错误主要是时间日期字段。尝试先导出数据然后强制它为ANSI并删除任何BoM并重新导入它。