2011-04-28 95 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

將調試模式設置爲'中斷所有錯誤'將使程序執行停止在導致錯誤的行,即使錯誤處理程序已被正確寫入。這可能會造成混淆,因爲看起來錯誤處理不起作用。