Страницы: 1
RSS
On Error игнорирует ошибку в первый раз, но не игнорирует во второй
 
Друзья, добрый день!
В этой теме при решении столкнулся с такой проблемой.
Через VBA создаю PQ запросы. Имя запроса, имя таблицы и имя листа берутся из таблицы DistinctValues.
При повторном запуске кода, хочу чтобы если такой запрос/лист уже есть, то просто переходило к следующему значению в списке DistinctValues.
Сейчас подумал, понимаю, что тупанул и можно просто проверить есть ли лист с таким названием в книге, но все равно интересно следующее:
Ставлю On Error Resume Next, чтобы когда возникнет ошибка, что запрос с таким именем уже существует, что-то с этим сделать.
Ставлю MsgBox Err.Number, получаю код ошибки и увожу на ErrHandler. Т.е. в первом цикле все хорошо.
Но во втором, получаю тот же код ошибки, но при этом Resume Next Не срабатывает и открывается дебагер.
Почему так себя ведет, в чем ошибка?

Спасибо.
Код
 
Добрый день.
После того, как по ошибке произошел переход выполнения кода на метку, все последующие операторы On Error... игнорируются, и выполнение кода остановится на первой же ошибке.
Есть недокументированный вариант после метки ErrHandler: написать строку кода On Error GoTo -1
Но так не рекомендуется делать.
В Вашем случае с On Error Resume Next можно было бы проверять что-то (наличие листа и т.п.) заранее, или использовать, например, такую структуру кода:
Код
Sub Макрос1()
  
  Dim cell
  
  ' ...
  
  On Error Resume Next
  
  For Each cell In Range("DistinctValues").Cells
    
    Err.Clear
    ActiveWorkbook.Queries.Add Name:=cell.Value ' ...

    If Err.Number = 0 Then
      ' При отсутствии ошибки выполнить действия
      ' ...
    End If
  
  Next
  
End Sub


Пример кода, поясняющий работу после перехода по ошибке на метку:
Код
Sub Test()
  
  Dim i As Long
  
  ' По ошибке - перейти на метку on_error
  On Error GoTo on_error
 
  ' Обращение к несуществующему листу
  With Worksheets("WrongName")
    
    ' Сюда выполнение кода не попадет
    Debug.Print 1
    
  End With
  
  Exit Sub

on_error:
  
  ' Код, выполняемый при ошибке.
  ' Всё, что будет выполняться после этого (в цикле или без), будет игнорировать любые On Error...
  ' и останавливать код на строке с новой возникшей ошибкой
  
  Debug.Print 2, Err.Description, Err.Number
  
  'On Error GoTo -1 ' Это недокументированное снятие игнора последующих OnError
  
  ' Оператор On Error ниже будет проигнорирован, ошибка деления на ноль остановит код
  On Error Resume Next
  i = 1 / 0
  
  Debug.Print 3, Err.Description, Err.Number

End Sub
Изменено: ZVI - 02.10.2022 17:08:33
 
ZVI, спасибо большое, очень интересно, теперь все понятно :-)
 
Владимир, большое спасибо!
Владимир
 
Друзья, рад развлечь немного чем-то необычным :)
 
Цитата
whateverlover написал:
теперь все понятно :-)
На мой взгляд, количество непоняток просто удвоилось
Было не понятно, почему не работает  GoTo 0
Яснее не стало, но добавилось почему работает  GoTo -1
 
ZVI, благодарю за подробный разбор (а whateverlover — за вопрос)!  :idea:
Очень неочевидное поведение, однако…  :sceptic:
Изменено: Jack Famous - 03.10.2022 09:51:16
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
 
Так как очень редко использую On Error GoTo xxx, пользуюясь рекомендацийе из документации
The On Error Resume Next construct may be preferable to On Error GoTo when handling errors generated during access to other objects. Checking Err after each interaction with an object removes ambiguity about which object was accessed by the code. You can be sure which object placed the error code in Err.Number, as well as which object originally generated the error (the object specified in Err.Source).
то и правда поведение описанное сюрприз. Собственно получаем что On Error GoTo xxx можно без проблем использовать в линейной процедуре без циклов.
По вопросам из тем форума, личку не читаю.
 
Заметил такой нюанс при обработке ошибок. Если при вклченном пропуске ошибок из макроса выполнить другой макрос, то внем откючить пропуск (невозможно?). А такая конструкция вызывает безконечный цикл в дочернем макросе.
Код
Sub testErr1()
    Dim a
    On Error Resume Next
    a = 2 / 0
'    On Error GoTo 0
    testErr2 a
End Sub
Sub testErr2(a)
    Dim b
    On Error GoTo metka
metka:
    On Error GoTo -1
    b = 2 * 3
    a = 2 / 0
End Sub
 
testuser, всё логично, вроде
On Error GoTo -1 лучше не использовать, кстати (писалось выше)
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
Страницы: 1
Наверх