2016-04-16 2 views
0

Я хочу удалить все строки из листа3, где sheet3 Значение столбца «N» не находится между листом «Основная» ячейка B12 и значение D12. Так что я попытался с помощью следующего кодаУдалить группу строк

With ActiveSheet 
    Lvl = ActiveSheet.Cells(Rows.Count, "A").End(xlUp).Row 
    .AutoFilterMode = False 
    .Range("N1").AutoFilter Field:=14, Criteria1:="<" & _ 
     Format(Sheets("Main").Cells(12, 2), "DD-MM-yyyy") 
    .Offset(1).SpecialCells(12).EntireRow.Delete 
    .AutoFilterMode = False 
end with 

Но это дает ошибку на Смещение линия Объект не поддерживает это свойство или метод

+0

.offset является свойством объекта Range, а не объект рабочего листа – Rosetta

ответ

1

Пара вещей здесь. Хорошей практикой является избегать ActiveSheet. Определите объект листа и установите его на этот лист. Это значительно облегчает ссылку на ваш код в дальнейшем.

Dim wsMain as Worksheet 
Set wsMain = thisworkbook.sheets("Main") 

Затем определите диапазон на этом листе, который вы должны автофильтировать и удалить строки, соответствующие вашим критериям. Редактировать: вы хотите изменить фильтр, чтобы отобразить ячейки, соответствующие вашим критериям, и затем удалить этот выбор.

wsMain.AutoFilterMode = false 
'format wsMain however you'd like in here 
Dim lRow, lCol as Integer 
    lRow = wsMain.Cells(Rows.Count, 1).End(xlUp).Row 
    lCol = wsMain.Cells(1, Columns.Count).End(xlToLeft).Column 
Dim rngTar as Range 
    Set rngTar = wsMain.Range(wsMain.Cells(1, 1), wsMain.Cells(lRow, lCol)) 
With rngTar 'filter to show everything that matches the values in the range you specified 
    .AutoFilter Field:=14, Criteria1:=">=wsMain.Range("B12:D12") 
    .Offset(1, 0).SpecialCells(xlCellTypeVisible).EntireRow.Delete 
End With 
wsMain.AutoFilterMode = false 

Edit:, если вы хотите иметь несколько фильтров, просто добавьте еще одну линию .Autofilter!

With rngTar 
    .AutoFilter Field:=14, Criteria1:=">=wsMain.Range("B12:D12") 
    .AutoFilter Field:=17, Criteria1:="Inactive" 
    .Offset(1, 0).SpecialCells(xlCellTypeVisible).EntireRow.Delete 
End With 

Надеюсь, это поможет!

+0

меняем согласно этому кодирование wsMain является таблицей, где я хочу, чтобы удалить строки и имя листа «Sheet3» Критерии значения дата хранится в имени листа " Главный". Поэтому я использую этот код, как Set wsMain = thisworkbook.sheets ("Лист3") и .AutoFilter поле: = 14, факторам1:. = "<" И листы ("Основные") клетки (12, 2) «Столбец B12 с рабочего листа Главная Но это не работает –

+0

Знаете ли вы, что ваш фильтр работает правильно? – David

+0

Другое дело. Вам нужно будет отменить свой фильтр, чтобы ** показать ** ячейки, соответствующие вашим критериям. Кроме того, попробуйте это по вашим критериям: «Criteria1: =»> = «& wsMain.Range (« B12: D12 »), Operator: = xlAnd' – David

0

Есть несколько неправильных вещей и несколько, которые могут быть улучшены в этом фрагменте кода.

а) 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 

Filter_Improvement_BeforeFilter_Improvement_After
Примеры данных перед процедуройПримеры данных после процедуры

Хотя вы и не делать все так же, как я надеюсь, что это помогает направить вас вправо направление.


¹ Существует также Rows.Count, который не имеет префикса характер. Теоретически вы можете столкнуться с проблемой, если код запускался на XLS (с 65536 строками), а ActiveSheet property был проведен XLSX (с 1048576 строками). Я лично не подписываюсь на эту практику все время по другим причинам (см. this).

+0

Что касается вашего добавления для дополнительной колонки фильтра: этот запрос эффективно отображает оба ответа, которые были отправлены недействительными, и превращает это в [Вопрос о русской кукле] (http://meta.stackexchange.com/questions/188625). Лучше обновить код до рабочей модели и попытаться добавить еще один столбец для фильтрации.Если это не удастся, задайте другой вопрос, касающийся этой ситуации. – Jeeped

Смежные вопросы