J'ai une grande fiche technique que je souhaite rechercher dans VBA sur la base de 3 ensembles de critères . Chaque entrée de ligne peut être considérée comme unique. Le format de la feuille/des données elles-mêmes ne peut pas être modifié en raison des exigences. (J'ai vu plusieurs articles sur des questions connexes, mais je n'ai pas encore trouvé de solution de travail pour cela.)
Au début, j'ai utilisé la méthode classique VBA find en boucle:
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
Mais comme cela doit être appelé un certain nombre de fois sur de grands ensembles de données, la vitesse n'était pas bonne.
J'ai fait quelques recherches et j'ai découvert que je pouvais utiliser la méthode match avec index . J'ai donc essayé sans succès de nombreuses variantes de cela, telles que:
result = Evaluate("=MATCH(1, (""" & criteria1Name & """=A2:A" & lastRow & ")*(""" & criteria2Name & """=B2:B" & lastRow & ")*(""" & criteria3Name & """=C2:C" & lastRow & "), 0)")
Et
result = Application.WorksheetFunction.Index(resultRange, Application.WorksheetFunction.Match((criteria1Name = criteria1Range)*(criteria2Name = criteria2Range)*(criteria3Name = criteria3Range))
Et
result = Application.WorksheetFunction.Index(resultRange, Application.WorksheetFunction.Match((criteria1Range=criteria1Name )*(criteria2Range=criteria2Name )*(criteria3Range=criteria3Name ))
Ensuite, j'ai essayé d'utiliser AutoFilter pour trier:
.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
Mais comme l'une des colonnes de tri contient des dates, j'ai eu des problèmes pour que le filtre automatique fonctionne correctement.
Ma question est, comment puis-je rechercher dans les colonnes dans Excel VBA en fonction de plusieurs critères, sans boucle, en retournant le numéro de ligne ou la valeur dans la cellule de cette ligne qui m'intéresse ?
Vous pouvez utiliser un filtre avancé. Placez les en-têtes de colonne dans une partie distincte de la feuille (ou une feuille complètement différente). Sous ces en-têtes de colonne, placez les critères que vous recherchez dans chaque colonne. Nommez ensuite cette plage (y compris les en-têtes) quelque chose comme "Critères". La macro devient alors:
Sub Macro1()
Sheets("Sheet1").Range("A1").CurrentRegion.AdvancedFilter xlFilterInPlace, Range("Criteria")
End Sub
Pour faire suite à mon commentaire ci-dessous, pour que le VBA crée la plage de critères dans les coulisses:
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
Vous pouvez utiliser EVALUATE
pour plusieurs critères comme pour renvoyer les numéros de ligne des valeurs mathématiques. Cela utilise la même approche que Est-il possible de remplir un tableau avec des numéros de ligne qui correspondent à certains critères sans boucle?
fred
1/1/2001
Apple
dans la colonne 5x
(lignes 1 et 5 dans l'image ci-dessous)
code
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
est limité à 65536 cellules, donc une plage plus longue doit être "fragmentée" en morceaux.