Что делать, если автофильтр в VBA не возвращает данных?

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

Вот мой код:

With Workbooks(KGRReport).Worksheets(spreadSheetName).Range("A1:I" & lastrowinSpreadSheet)
    .AutoFilter Field:=3, Criteria1:=LimitCriteria, Operator:=xlFilterValues 'Do the filtering for Limit
     .AutoFilter Field:=9, Criteria1:=UtilizationCriteria, Operator:=xlFilterValues 'Do the filtering for Bank/NonBank
End With

'Clear the template
 Workbooks(mainwb).Worksheets("Template").Activate
 Workbooks(mainwb).Worksheets("Template").Rows(7 & ":" & Rows.Count).Delete

 'Copy the filtered data
 Workbooks(KGRReport).Activate
 Set myRange = Workbooks(KGRReport).Worksheets(spreadSheetName).Range("B2:H" & lastrowinSpreadSheet).SpecialCells(xlVisible)
 For Each myArea In myRange.Areas
     For Each rw In myArea.Rows
           strFltrdRng = strFltrdRng & rw.Address & ","
     Next
 Next

 strFltrdRng = Left(strFltrdRng, Len(strFltrdRng) - 1)
 Set myFltrdRange = Range(strFltrdRng)
 myFltrdRange.Copy
 strFltrdRng = ""

Это дает мне ошибку в

Set myRange = Workbooks(KGRReport).Worksheets(spreadSheetName).Range("B2:H" & lastrowinSpreadSheet).SpecialCells(xlVisible)

Когда данных вообще нет, возвращается ошибка: «Ячейки не найдены».

Пробовал обрабатывать ошибки, как это сообщение: 1004 Ошибка: ячейки не найдены, легко решение?

Но это не помогало. Нужен совет, как решить эту проблему.


person lakesh    schedule 12.04.2016    source источник
comment
Просто используйте что-то вроде: If Workbooks(KGRReport).Worksheets(spreadSheetName).Range("B2:H" & lastrowinSpreadSheet).RowHeight Then, если ничего не отображается, высота равна 0, что будет считаться False (все остальное будет считаться True)   -  person Dirk Reichel    schedule 12.04.2016
comment
FWIW связанный вопрос (и ссылка из этого вопроса, поскольку это был обман) должен был обеспечить жизнеспособный путь решения этой проблемы. То есть вам нужно обработать ошибку, если вы знаете, что есть шанс, что она будет выдана. Я даю подход, чтобы избежать обработки ошибок, но другие ответы по существу говорят то же самое, что и этот другой вопрос: обработать ошибку.   -  person Byron Wall    schedule 12.04.2016


Ответы (5)


Попробуйте обработку ошибок следующим образом:

Dim myRange As Range

On Error Resume Next
Set myRange = Range("your range here").SpecialCells(xlVisible)
On Error GoTo 0

If myRange Is Nothing Then
    MsgBox "no cells"
Else
    'do stuff
End If
person brettdj    schedule 12.04.2016
comment
где оператор перехода 0? где это должно быть написано? - person lakesh; 12.04.2016
comment
Это не оператор перехода, он очищает обработчик ошибок. - person brettdj; 12.04.2016

Подход без обработки ошибок

Можно построить AutoFilter таким образом, чтобы не выдавать ошибку, если ничего не найдено. Хитрость заключается в том, чтобы включить строку заголовка в вызов SpecialCells. Это гарантирует, что по крайней мере 1 строка будет видна, даже если ничего не найдено (Excel не будет скрывать строку заголовка). Это предотвращает зависание выполнения из-за ошибки и дает вам набор ячеек для проверки того, были ли найдены данные.

Чтобы проверить, есть ли данные в результирующем диапазоне, вам нужно проверить Rows.Count > 1 Or Areas.Count > 1. Это обрабатывает два возможных случая, когда ваши данные находятся непосредственно под заголовком или в прерывистом диапазоне под строкой заголовка. Любой результат означает, что AutoFilter нашел допустимые строки.

Как только вы убедитесь, что данные были найдены, вы можете выполнить желаемый вызов SpecialCells только для данных, не беспокоясь об ошибке.

Пример данных [столбец C (поле 2) будет отфильтрован]:

случайные данные

Sub TestAutoFilter()

    'this is your block of data with headers
    Dim rngDataAndHeader As Range
    Set rngDataAndHeader = Range("B2").CurrentRegion

    'this will knock off the header row if you want data only
    Dim rngData As Range
    Set rngData = Intersect(rngDataAndHeader, rngDataAndHeader.Offset(1))

    'autofilter
    rngDataAndHeader.AutoFilter Field:=2, Criteria1:=64

    'get the visible cells INCLUDING the header row
    Dim rngVisible As Range
    Set rngVisible = rngDataAndHeader.SpecialCells(xlCellTypeVisible)

    'check if there are more than 1 rows or if there are multiple areas (discontinuous range)
    If rngVisible.Rows.Count > 1 Or rngVisible.Areas.Count > 1 Then
        Debug.Print "found data"

        'data is available, this call cannot throw an error now
        Set rngVisible = rngData.SpecialCells(xlCellTypeVisible)

        'do your normal execution here
        '
        '
        '
    Else
        Debug.Print "only header, no data included"
    End If
End Sub

Результат с критериями 1:=64

Immediate window: found data

введите здесь описание изображения

Результат с критериями 1:=0

Immediate window: only header, no data included

введите здесь описание изображения

Другие примечания:

  • Код включает отдельную переменную с именем rngData, если вы хотите получить доступ к данным без заголовков. Это просто INTERSECT-OFFSET, чтобы поднять его на одну строку вниз.
  • В случае, когда результат был найден, код сбрасывает rngVisible, чтобы он отображал только видимые ячейки в данных (пропускает заголовок). Поскольку сейчас этот вызов не может завершиться ошибкой, он безопасен без обработки ошибок. Это дает вам диапазон, который соответствует тому, что вы пробовали в первый раз, но без шанса получить ошибку. Это не требуется, если вы можете обработать исходный диапазон rngVisible, включающий заголовки. Если это так, то вы можете полностью отказаться от rngData (если только вам это не нужно).
person Byron Wall    schedule 12.04.2016

поскольку вы используете myRange в качестве реального результата действия фильтрации, вы можете сделать следующее

Dim wbKGRR As Workbook  '<== better set variable for workbooks you'll work with: it saves both typing time and possible errors
Dim ws As Worksheet  '<== better set variable for worksheets you'll work with: it saves both typing time and possible errors

'...


Set wbKGRR = Workbooks(KGRReport) '<== better set variable for workbooks: it saves both typing time and possible errors
Set ws = wbKGRR.Worksheets(spreadSheetName)  '<== better set variable for worksheets you'll work with: it saves both typing time and possible errors

With ws
    With .Range("A1:I" & lastrowinSpreadSheet)
        .AutoFilter Field:=3, Criteria1:=LimitCriteria, Operator:=xlFilterValues 'Do the filtering for Limit
        .AutoFilter Field:=9, Criteria1:=UtilizationCriteria, Operator:=xlFilterValues 'Do the filtering for Bank/NonBank
    End With
    If Application.WorksheetFunction.Subtotal(103, .Columns("B")) > 0 Then Set myRange = .Range("B2:H" & lastrowinSpreadSheet).SpecialCells(xlVisible) '<== myRange will be set only if filtering has left some visible cells
End With


'Clear the template
'Workbooks(mainwb).Worksheets("Template").Activate '<== no need to activate
Workbooks(mainwb).Worksheets("Template").Rows(7 & ":" & Rows.Count).Delete

'Copy the filtered data
' Workbooks(KGRReport).Activate '<== no need to activate
If Not myRange Is Nothing Then '<== "myRange" has been set properly if previous Autofilter method has left some visbile cells
    For Each myArea In myRange.Areas
        For Each rw In myArea.Rows
              strFltrdRng = strFltrdRng & rw.Address & ","
        Next rw
    Next myArea

    strFltrdRng = Left(strFltrdRng, Len(strFltrdRng) - 1)
    Set myFltrdRange = Range(strFltrdRng)
    myFltrdRange.Copy
    strFltrdRng = ""
End If

где я также предложил некоторые настройки переменных рабочей книги и рабочего листа, чтобы «облегчить» жизнь кодирования

person user3598756    schedule 12.04.2016

Вы можете поместить удар кода в функцию.

Set myRange = Workbooks(KGRReport).Worksheets(spreadSheetName).Range("B2:H" & lastrowinSpreadSheet).SpecialCells(xlVisible)

В функции используйте при ошибке goto xxxx. Когда ошибка ничего не возвращает из функции, используйте «если myRange не является ничем, то», чтобы игнорировать ячейки с ошибкой.

person Jason    schedule 12.04.2016
comment
Это было бы яснее, если бы он включал пример кода для создания поведения, которое вы описываете. Я верю, что это сработает, но может быть не очевидно, как реализовать это предложение. - person Byron Wall; 12.04.2016

Ни один из ответов ниже не работал для меня. Вот что я наконец нашел, что сработало:

Sub fileterissues()

Dim VisibleRows as Long

‘Some code here

With Sheets(ws1).Range(“myrange”)
.Autofilter Field:=myfieldcolumn, criteria:=myfiltercriteria
VisibleRows = Application.Worksheetfunction.Subtotal(103, sheets(1).mycolumnfieldrange)
If VisibleRows = 0 then Resume Next
End with

‘More code

End sub
person Community    schedule 10.08.2018