При ошибке GoTo не работает; Разрывы кода - PullRequest
5 голосов
/ 28 апреля 2011

Я пишу функцию VBA для импорта данных из одной таблицы в другую в Access.Таблица, в которую я импортирую, имеет более строгие ограничения данных (например, типы, размер и т. Д.), Поэтому я ожидаю много ошибок.

Вместо того, чтобы просеивать каждую возникающую ошибку VBA, я хочу, чтобы мой цикл набора записей пропускал всю текущую запись и записывал ее в отдельную таблицу при возникновении ошибки.Таким образом, каждая вторая строка, которую я вставил On Error GoTo RecordError.Но по некоторым причинам это не обрабатывает каждую ошибку.Мой код просто ломается и говорит мне, в чем ошибка.У меня уже отмечена опция «Разрывать необработанные исключения».

Вот скриншот, который должен это объяснить.Even by itself, this screenshot seems to make no sense to me.

Почему он прерывается на линии сразу после обработчика ошибок?

Ответы [ 7 ]

3 голосов
/ 28 апреля 2011

Я думаю, вы не понимаете, как работает обработка ошибок 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 объект сразу после любой строки, которая может вызвать ошибку (если Err.Number равно нулю (0), оператор завершился успешно, не выдав ошибку).Это способ слишком много работы для большинства ситуаций.
    4. On Error GoTo 0: отключает обработку ошибок.

Учитывая это, этообычно помещают оператор On Error... сразу после объявления процедуры (оператор Sub или Function), хотя некоторые люди помещают свои операторы Dim между ними.Если вы хотите временно изменить способ обработки ошибок в подпрограмме, поместите «новый» прямо перед кодом, к которому он должен применяться, и (если используется), «верните» (переиздав оригинал) сразу после. 1043нет активной обработки ошибок (и я был бы удивлен, если бы это скомпилировалось, если бы это было так).

Обратите внимание, что Дэвид Хеффернан дал вам основную часть этого в своем ответе, и это было здесь перед моим ....

2 голосов
/ 20 марта 2013

Причина, по которой он не работает, заключается в том, что вы не можете использовать On Error Goto ... в обработчике ошибок.

see http://www.cpearson.com/excel/errorhandling.htm

, вы не можете использовать On Error, чтобы пропустить несколькоСтроки, вместо ошибки должны идти в обработчик ошибок, который затем возобновляет на нужную следующую строку (в вашем примере вы, вероятно, могли бы избежать использования одного обработчика ошибок, который содержит возобновление, следующее, которое вернет вас к следующему полю).

благодаря Тиму Уильямсу (Tim Williams) по этому вопросу: Второе из 2 операторов 'On Error goto' игнорируется

, и BTW ParseInt на ZIP уничтожит почтовые индексы, которые начинаются с0, почтовые индексы, вероятно, следует рассматривать как текст.

1 голос
/ 15 февраля 2015

Установка режима отладки на «разбить все ошибки» приведет к остановке выполнения программы в строке, которая вызывает ошибку, даже если обработчик ошибок был правильно написан. Это может сбивать с толку, поскольку кажется, что обработка ошибок не работает.

1 голос
/ 29 апреля 2011

Обработка ошибок с VBA - это настоящая PITA.Я бы предложил вам взглянуть на этот ответ на вопрос "MS-Access, VBA и обработка ошибок" и адаптировать его к вашей собственной ситуации.Вы можете легко записать некоторый код, который будет хранить все ваши сообщения об ошибках в таблице, создавая де-факто систему отчетов об ошибках.

1 голос
/ 28 апреля 2011

Вам необходимо поместить строку On Error перед кодом, ошибки которого вы хотите обработать.

Более того, вам нужна только одна строка On Error.Затем обработчик ошибок остается активным до выхода из подпрограммы или до выполнения другого оператора On Error.

0 голосов
/ 06 февраля 2015

Я тоже видел ошибку обработки.Вот один пример.

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

Обратите внимание, что обработчик ошибок не выполнен.В этом случае для формы, вызвавшей возвращаемый код, в качестве источника записи на лету был задан пустой набор записей, поэтому поля на экране не видны.Форма является непрерывной, поэтому записи и поля не отображаются, когда форма загружается с пустым набором записей.Функция have () напрямую не вызывается моим кодом, но, похоже, она вызывается методом me.requery.Метод have () вызывался в моем коде сотни миллионов раз, но это единственный экземпляр, который приводит к его сбою, и обработчик ошибок не задействован.

Оригинальный вопрос Лэнсу Робертсу.Unicode utf-8 может иногда портить ms-access, так как кажется, что данные могут быть перепутаны для командных кодов (я думаю).utf-8 может попасть в ваши данные, если данные изначально были загружены из текстового файла.utf-8 с меткой порядка байтов (BoM) особенно неприятен.Когда вы запускаете процедуру, которая работает с данными, могут возникнуть странные ошибки, и может показаться, что ваш файл поврежден.В других случаях функции обработки текста дают неправильные ответы, например Mid () увидит спецификацию, и если вы укажете начальную точку, она начнется с спецификации, но Len () проигнорирует спецификацию.Я предполагаю, что если у вас есть эта проблема, то ms-доступ не может правильно обрабатывать ошибки.У меня были похожие проблемы с импортом данных и импортом utf-8, так как причиной была ANSI.Обратите внимание, что utf-8 и ANSI в большинстве случаев идентичны для простых английских данных, поэтому ваши ошибки могут быть не в каждой строке.Мои ошибки были в основном с полями даты и времени.Попробуйте сначала экспортировать данные, а затем сделать так, чтобы они были в формате ANSI, удалить любой BoM и повторно импортировать их.

0 голосов
/ 29 апреля 2011

Никто действительно не ответил на ваш вопрос.

Скажите, что ваш код выглядит примерно так (скелетная структура):

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, но вы заменили бы их реальными номерами ошибок, которые вместо этого хотите игнорировать.

Вы не хотите игнорировать каждую ошибкупотому что вы могли бы в конечном итоге игнорировать важные ошибки в другом месте вашей подпрограммы.Если вы не хотите выяснять, каково ограниченное число ошибок, которые вы хотите игнорировать, я бы предложил установить флаг в начале блока кода, который генерирует ошибки, которые вы хотите игнорировать, а затем использовать`If ​​bolErrorInCodeBlockToIgnore Then, чтобы решить, игнорируете ли вы все ошибки или нет.Примерно так:

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

Я бы предпочел первое, поскольку я твердо верю только в игнорирование известных ошибок, а не в любую старую ошибку, которая случается.Но может быть довольно сложно придумать тесты, которые будут выдавать все возможные ошибки, которые вы хотите игнорировать.

...