2013-12-24 4 views
5

У меня есть большой лист данных, который я хочу найти в VBA на основе 3 наборов критериев. Каждая запись строки может считаться уникальной. Формат самого листа/данных не может быть изменен из-за требований. (Я видел несколько сообщений о связанных с этим вопросов, но не нашли рабочее решение для этого еще.)VBA (Excel): Найти на основе нескольких критериев поиска без петли

Сначала я использовал классический метод VBA find в цикле:

Set foundItem = itemRange.Find(What:=itemName, Lookin:=xlValues, lookat:=xlWhole, SearchOrder:=xlByRows) 
If Not foundItem Is Nothing Then 
    firstMatchAddr = foundItem.Address 
    Do 
     ' *Check the other fields in this row for a match and exit if found* 
     Set foundItem = itemRange.FindNext(foundItem) 
    Loop While foundItem.Address <> firstMatchAddr And Not foundItem Is Nothing 
End If 

Но так как это нужно называть несколько раз на больших наборах данных, скорость которой не была хорошей.

Я искал и обнаружил, что могу использовать метод match с index. Поэтому я безуспешно пытался много вариантов, что такие, как:

result = Evaluate("=MATCH(1, (""" & criteria1Name & """=A2:A" & lastRow & ")*(""" & criteria2Name & """=B2:B" & lastRow & ")*(""" & criteria3Name & """=C2:C" & lastRow & "), 0)") 

И

result = Application.WorksheetFunction.Index(resultRange, Application.WorksheetFunction.Match((criteria1Name = criteria1Range)*(criteria2Name = criteria2Range)*(criteria3Name = criteria3Range)) 

И

result = Application.WorksheetFunction.Index(resultRange, Application.WorksheetFunction.Match((criteria1Range=criteria1Name)*(criteria2Range=criteria2Name)*(criteria3Range=criteria3Name)) 

Затем я попытался с помощью AutoFilter сортировать:

.Range(.Cells(1,1), .Cells(lastRow, lastCol)).AutoFilter Field:=1, Criteria1:="=" & criteria1Name 
.Range(.Cells(1,1), .Cells(lastRow, lastCol)).AutoFilter Field:=2, Criteria1:="=" & criteria2Name 
.Range(.Cells(1,1), .Cells(lastRow, lastCol)).AutoFilter Field:=3, Criteria1:="=" & criteria3Name 

Но потому что один из сортировка столбцов содержит даты, у меня были проблемы с тем, чтобы AutoFilter работал правильно.

Мой вопрос, как я могу искать через столбцы в Excel VBA на основе нескольких критериев, без зацикливания, возвращая либо номер строки или значение в ячейке этой строки, что я заинтересован в?

+0

Почему вы против зацикливания? Сколько строк вы говорите? – Graphth

+0

Что вы делали с возвращенными результатами? – brettdj

ответ

5

Вы можете использовать Расширенный фильтр. Поместите заголовки столбцов в отдельную часть листа (или совсем другой лист). Под этими заголовками столбцов укажите критерии, которые вы ищете в каждом столбце. Затем назовите этот диапазон (включая заголовки) чем-то вроде «Criteria». Затем макрос становится:

Sub Macro1() 

    Sheets("Sheet1").Range("A1").CurrentRegion.AdvancedFilter xlFilterInPlace, Range("Criteria") 

End Sub 

В продолжение на мой комментарий ниже, чтобы иметь VBA создать критерии варьируются негласно:

Sub Macro1() 

    'Code up here that defines the criteria 

    Application.ScreenUpdating = False 
    Application.DisplayAlerts = False 

    With Sheets.Add 
     'Create the advanced filter criteria range 
     .Range("A1") = "HeaderA" 
     .Range("B1") = "HeaderB" 
     .Range("C1") = "HeaderC" 
     .Range("A2") = criteria1Name 
     .Range("B2") = criteria2Name 
     .Range("C2") = criteria3Name 

     'Alternately, to save space: 
     '.Range("A1:C1").Value = Array("HeaderA", "HeaderB", "HeaderC") 
     '.Range("A2:C2").Value = Array(criteria1Name, criteria2Name, criteria3Name) 

     'Then perform the advanced filter 
     Sheets("Sheet1").Range("A1").CurrentRegion.AdvancedFilter xlFilterInPlace, .Range("A1:C2") 

     'Remove behind the scenes sheet now that the filter is completed 
     .Delete 
    End With 

    Application.ScreenUpdating = True 
    Application.DisplayAlerts = True 

End Sub 
+0

Это интересный подход. Однако я не могу изменить содержание книги, и набор критериев является динамическим, основанным на другом наборе входных данных. Я действительно ищу способ сделать это исключительно в VBA. – user1205577

+0

Вы можете создать диапазон критериев в vba, даже создать рабочий лист temp, который впоследствии будет удален, просто отключите отображение экрана и пользователь никогда не увидит за кулисами вещи – tigeravatar

+0

Я обновил ответ, чтобы расширить то, о чем я говорил в мой предыдущий комментарий – tigeravatar

3

Вы можете использовать EVALUATE для нескольких критериев, как так верните номера строк значений математики.При этом используется тот же подход, что Is it possible to fill an array with row numbers which match a certain criteria without looping?

  • Она ищет 50000 строк, чтобы соответствовать
    • первые четыре буквы в колонке А матчей fred
    • даты в B, чтобы быть больше, чем 1/1/2001
    • apple в колонка 5
  • Любые строки, соответствующие этим критериям, перенастраиваются как номера строк в x

(строк 1 и 5 в картинке ниже)

кода

Sub GetEm2() 
x = Filter(Application.Transpose(Application.Evaluate("=IF((LEFT(A1:A10000,4)=""fred"")*(B1:B10000>date(2001,1,1))*(C1:C10000=""apple""),ROW(A1:A10000),""x"")")), "x", False) 
End Sub 

Application.Transpose ограничена 65536 клеток, так что больше диапазон должен быть " куски "на куски.

enter image description here

+0

Ты запустишь добавить код 'Dim x' в код? После того, как номер строки хранится в x, как бы вы отфильтровываете эти строки? Tks. –

+0

Нет, X - вариант. – brettdj

+0

Так что да, он забыл добавить 'Dim x как Variant'. Всегда используйте 'Dim', даже для вариантов. –

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