Друзья, добрый день! В этой теме при решении столкнулся с такой проблемой. Через VBA создаю PQ запросы. Имя запроса, имя таблицы и имя листа берутся из таблицы DistinctValues. При повторном запуске кода, хочу чтобы если такой запрос/лист уже есть, то просто переходило к следующему значению в списке DistinctValues. Сейчас подумал, понимаю, что тупанул и можно просто проверить есть ли лист с таким названием в книге, но все равно интересно следующее: Ставлю On Error Resume Next, чтобы когда возникнет ошибка, что запрос с таким именем уже существует, что-то с этим сделать. Ставлю MsgBox Err.Number, получаю код ошибки и увожу на ErrHandler. Т.е. в первом цикле все хорошо. Но во втором, получаю тот же код ошибки, но при этом Resume Next Не срабатывает и открывается дебагер. Почему так себя ведет, в чем ошибка?
Спасибо.
Код
Код
Sub Макрос1()
For Each objConnection In ThisWorkbook.Connections
'Get current background-refresh value
bBackground = objConnection.OLEDBConnection.BackgroundQuery
'Temporarily disable background-refresh
objConnection.OLEDBConnection.BackgroundQuery = False
'Refresh this connection
objConnection.Refresh
'Set background-refresh value back to original value
objConnection.OLEDBConnection.BackgroundQuery = bBackground
Next
For Each cell In Range("DistinctValues")
On Error Resume Next
ActiveWorkbook.Queries.Add Name:=cell.Value, Formula:= _
"let" & Chr(13) & "" & Chr(10) & " Источник = Excel.CurrentWorkbook(){[Name=""Таблица""]}[Content]," & Chr(13) & "" & Chr(10) & " ChangeType = Table.TransformColumnTypes(Источник,{{""№"", Int64.Type}, {""код"", type text}, {""Ограничения"", type text}})," & Chr(13) & "" & Chr(10) & " ToRows = Table.ToRows(ChangeType)," & Chr(13) & "" & Chr(10) & " RecordsToRemove = Table.ToRows(#""Задублированные строки"")," & Chr(13) & "" & Chr(10) & " DuplicatesRemoves = Table.FromRows(List.RemoveMatchin" & _
"gItems(ToRows,RecordsToRemove), Table.ColumnNames(ChangeType))," & Chr(13) & "" & Chr(10) & " Filter = Table.SelectRows(DuplicatesRemoves, each ([Ограничения] = """ & cell.Value & """))" & Chr(13) & "" & Chr(10) & "in" & Chr(13) & "" & Chr(10) & " Filter"
MsgBox Err.Number
On Error GoTo ErrHandler
ActiveWorkbook.Worksheets.Add
With ActiveSheet.ListObjects.Add(SourceType:=0, Source:= _
"OLEDB;Provider=Microsoft.Mashup.OleDb.1;Data Source=$Workbook$;Location=" & cell.Value & ";Extended Properties=""""" _
, Destination:=Range("$A$1")).QueryTable
.CommandType = xlCmdSql
.CommandText = Array("SELECT * FROM [" & cell.Value & "]")
.RowNumbers = False
.FillAdjacentFormulas = False
.PreserveFormatting = True
.RefreshOnFileOpen = False
.BackgroundQuery = True
.RefreshStyle = xlInsertDeleteCells
.SavePassword = False
.SaveData = True
.AdjustColumnWidth = True
.RefreshPeriod = 0
.PreserveColumnInfo = True
.ListObject.DisplayName = "_" & Replace(Replace(cell.Value, " ", "_"), ",", "")
.Refresh BackgroundQuery:=False
End With
ActiveSheet.Name = cell.Value
ErrHandler:
'On Error GoTo 0
Next cell
End Sub
Добрый день. После того, как по ошибке произошел переход выполнения кода на метку, все последующие операторы 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
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
Так как очень редко использую 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 лучше не использовать, кстати (писалось выше)
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄