Есть несколько неправильных вещей и несколько, которые могут быть улучшены в этом фрагменте кода.
а) With ... End With statement
With ActiveSheet
...
End With
Вы должны знать, что рабочий лист вы находитесь. Вышеприведенное может быть полезно, если вы планируете выполнить его на одном листе, а затем активировать другое и выполнить его снова, но вы также можете прокручивать рабочие листы.
б) Redundantly ссылки на листе
Lvl = ActiveSheet.Cells(Rows.Count, "A").End(xlUp).Row
Вы определили таблицу должны быть обработаны в вашем With ... End With statement. Нет необходимости продолжать ссылаться на него, пока вы префикс Range и Range.Cells объектов с .
(DOT) №.
с) Начиная с новой Range.AutoFilter Method
.AutoFilterMode = False
...
.AutoFilterMode = False
Хороший код здесь. Я лично проверяю, есть ли автофильтр (например, if .AutoFilterMode then .AutoFilterMode = False
), прежде чем отключать его, но нет ничего плохого в прямой перезаписи независимо от исходного значения. Всегда полезно отключить его до выхода, если он не нужен для пользователя.
Может быть, стоит отметить, что при использовании на клетках в .CurrentRegion property или .UsedRange property в Range.Parent property должен быть добавлен в качестве .AutoFilterMode является собственностью Worksheet Object, не Range object. (см. пример ниже)
d) В какой колонке установлен Range.AutoFilter Method?
.Range("N1").AutoFilter Field:=14, Criteria1:="<" & _
Format(Sheets("Main").Cells(12, 2), "DD-MM-yyyy")
Да колонка N является 14-й колонки относительно листа, но если вы собираетесь установить автофильтра, как это, то это может быть один и только столбец относительно столбца N. .Range("N1")
должен быть .Range("N:N")
и это должно быть Field:=1
для поддержания надежности, так как столбец N является первым и только столбец, когда вы смотрите только на колонке N.
е) Установка критериев Date-Type в Range.AutoFilter Method
Ваша дата строка не г чтобы интерпретироваться как дату, но как строку. Строки не могут быть надежно использованы с <
или >
операторами по критериям. Ваша лучшая надежда на успех состоит в том, чтобы использовать исходный Range.Value2 property с даты на главном листе с помощью менее оператора сравнения. (Смотри пример ниже)
е) Попытка переместить (ака .Offset) от листа
.Offset(1).SpecialCells(12).EntireRow.Delete
Вы работаете со всем листе, а не Range.CurrentRegion property или Worksheet.UsedRange property. Вы не можете взять 1048576 строк × 16384 столбцов и .Offset это одна ячейка в любом направлении, не изменяя ее сначала, потому что она попытается вытолкнуть одну строку или один столбец с рабочего листа.
В теории, вы могли бы Range.Resize блок ячеек, с которыми вы работаете, до тех пор, пока вы .Resize до .Offset.
'this works
.Resize(.Rows.Count-1, .Columns.Count).Offset(1).SpecialCells(12).EntireRow.Delete
this does not work
.Offset(1).Resize(.Rows.Count-1, .Columns.Count).SpecialCells(12).EntireRow.Delete
Кроме того, Range.Offset property является собственностью Range object, а не Worksheet Object и есть более эффективные способы борьбы с ограниченным количеством ячеек. (См CurrentRegion ниже)
г) В Range.Delete method и Range.SpecialCells method
Использование .SpecialCells с опцией xlCellTypeVisible не является строго необходимым при удалении строк и только добавляет больше обработки.
Просто отпустите строку заголовка, как вы это сделали, с командой .Offset (необязательно изменяя размер до одной строки меньше) и .Удалить .EntireRow.
Я предпочитаю, чтобы ячейки были удалены с родным листом SUBTOTAL function. Раньше была ошибка, когда не было видимых ячеек, и все ячейки до конца рабочего листа были включены, но я считаю, что исправлено с пакетами обновлений. Несмотря на это, проведение неразрушающего теста для видимых ячеек с помощью SUBTOTAL - хорошая практика кодирования.
z) Использование Range.CurrentRegion property.
Мои примеры для .CurrentRegion будет иметь дело с блоком клеток, исходящих от А1 до тех пор, пока не встречает совершенно пустую колонку в одном направлении и совершенно пустой строки в другой.
Хотя это не всегда так, это, безусловно, самый распространенный. Корректировки должны быть сделаны, если этот шаблон данных не соответствует вашим собственным.
Range.CurrentRegion property в With ... End With statement будет служить сосредотачиваться код на клетках, исходящих из одной клетки. Во многих случаях это похоже на Worksheet.UsedRange property, но определяется значениями только на листе, а не xlCellTypeLastCell property. Фактически, ваше использование Range("N1").AutoFilter
использует .CurrentRegion с центром в N1 в качестве начальной точки для определения диапазона .AutoFilter.
При использовании в With ... End With statement все ссылки в пределах ... End С блоком становится относительно .CurrentRegion; например Worksheet.Rows становится Range.Rows.
.CurrentRegion любой клетки можно исследовать, выбрав любую ячейку и нажав Ctrl + один раз. Он распространяется (излучается) во всех направлениях; не только вниз и вправо, если исходная ячейка не равна A1.
Ваш код изменен
Dim lvl As Long
With Worksheets("Sheet2")
'work with the block of cells radiating out from A1
With .Cells(1, 1).CurrentRegion
'if the parent worksheet already has an AutoFiltyer, remove it
If .Parent.AutoFilterMode Then .Parent.AutoFilterMode = False
lvl = .Rows.Count '<~~ not sure what LVL is actually used for but this is all that is needed
With .Range("N:N")
'filter on the raw numerical .value2 of the date
.AutoFilter Field:=1, _
Criteria1:="<" & Worksheets("Main").Cells(12, 2).Value2, _
Operator:=xlFilterValues
End With
'step off the header row
With .Resize(.Rows.Count - 1, .Columns.Count).Offset(1, 0)
'are there visible cells
If CBool(Application.Subtotal(103, .Cells)) Then
'don't need .SpecialCells(xlCellTypeVisible) here
.EntireRow.Delete
End If
End With
End With
'remove the AutoFilter
If .AutoFilterMode Then .AutoFilterMode = False
End With
Примеры данных перед процедуройПримеры данных после процедуры
Хотя вы и не делать все так же, как я надеюсь, что это помогает направить вас вправо направление.
¹ Существует также Rows.Count
, который не имеет префикса характер. Теоретически вы можете столкнуться с проблемой, если код запускался на XLS (с 65536 строками), а ActiveSheet property был проведен XLSX (с 1048576 строками). Я лично не подписываюсь на эту практику все время по другим причинам (см. this).
.offset является свойством объекта Range, а не объект рабочего листа – Rosetta