2011-04-28 54 views
5

我正在编写一个VBA函数来将数据从一个表导入到另一个表中。我输入的表具有更严格的数据约束(即类型,大小等),所以我期待着很多错误。On Error GoTo not working;代码中断

与其筛选出现的每个VBA错误,我都希望自己的记录集循环跳过整个当前记录,并在出现错误时将其记录在单独的表中。所以我插入的其他行都是On Error GoTo RecordError。但由于某些原因,它不处理每一个错误。我的代码只是打破了,告诉我错误是什么。我已经选中了“未处理异常中断”选项。

下面是应该解释它的屏幕截图。 Even by itself, this screenshot seems to make no sense to me.

为什么它会在错误处理程序后立即崩溃?

+0

你能提供一个你看到的错误信息的例子吗? – 2011-04-28 17:12:54

+0

错误消息不相关。该错误与我的数据库字段的格式有关,并且这是一个错误消息,如果未设置“On Error GoTo ...”,我会期望得到该错误消息。这是事实,我的代码打破了,而不是去我设置的标签。 – rdevitt 2011-04-29 02:46:10

+1

我问的原因是因为在Access中触发了一些无法使用VBA捕获的错误消息。 – 2011-04-29 12:13:26

回答

1

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

更重要的是,你只需要有一个On Error线。错误处理程序将保持活动状态,直到子例程退出或您执行另一个On Error语句。

+0

这是我的假设,但它似乎没有工作。我注释掉了所有“On Error GoTo RecordError”语句,除了第一个,我仍然得到相同的结果。只要我设置了'On Error GoTo ...',我的代码不应该在那个子程序中的任何地方进一步崩溃。对??除非我把'On Error'改成别的东西。 – rdevitt 2011-04-29 02:43:17

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:忽略错误&继续。有时在清理例程结束时有用(例如,如果要关闭可能打开或可能未打开的记录集)。或者,如果在任何可能的错误提示行(如果Err.Number为零(0),语句成功而没有引发错误)之后检查Err对象立即,也可以使用此表单。这是的方式对于大多数情况下工作太多。
    4. On Error GoTo 0:关闭错误处理。

鉴于此,它通常放置On Error...声明立即followng例程的声明(该SubFunction语句),虽然有些人把自己Dim语句之间。如果您想临时更改例程中的错误处理方式,请将“新”一个放在要应用的代码之前,并且(如果使用)放在“恢复”(重新发送原始文件)之后。

即使有这些,我也不知道为什么当选择“断开未处理的错误”时它会在错误抛出的行中断裂,除非你已经设法混淆了它,认为没有活动错误处理(如果情况确实如此,我会感到惊讶)。

需要注意的是大卫·赫弗南给你的这个重要组成部分在他的答案,并在这里我之前....用VBA

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 

我更倾向于第一种,因为我只知道忽略的错误,而不是发生任何旧的错误是一个坚定的信徒。但是想出可能会产生所有可能的错误的测试可能相当困难。

2

它不工作的原因是因为您不能在错误处理程序中使用On Error Goto ...。

看到http://www.cpearson.com/excel/errorhandling.htm

不能使用上的错误,跳过几行,就不是错误应该去一个错误处理程序,然后重新开始对所需的下一行(在你的榜样,你也许可以逃脱一个错误其中包含一个简历,它会带你回到下一个领域)。

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

,并在一个ZIP BTW parseInt函数将摧毁以0开头的邮递区号,邮编或许应该被视为文本。

+0

这是答案 - 在我的情况下,至少:我使用'On Error GoTo _label_'来跳过'For'循环中的一些代码行。谢谢! – 2016-04-27 08:29:35

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()在我的代码中被调用了数亿次,但这是唯一导致它失败并且错误处理程序未被启用的实例。

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

+0

谢谢Andoriyu, 我的系统被设置为打破所有错误,这是问题。 – AndrewM 2015-02-24 23:49:32

1

将调试模式设置为'中断所有错误'将使程序执行停止在导致错误的行,即使错误处理程序已被正确写入。这可能会造成混淆,因为看起来错误处理不起作用。