Kombinierte Suche in Excel mit mehreren Treffern
Suchfunktion mit mehreren ODER-Konnektoren und einer Trefferliste
Hallo zusammen,
ist es möglich in Excel mittels VBA eine Suchfunktion mit einer beliebigen Anzahl von ODER-Konnektoren zu erstellen, so dass ich eine Liste mit den Zeilen/Zellen bekommen, die die Treffer beinhalten, so wie in Access?
Grüße
Alexander
Hallo zusammen,
ist es möglich in Excel mittels VBA eine Suchfunktion mit einer beliebigen Anzahl von ODER-Konnektoren zu erstellen, so dass ich eine Liste mit den Zeilen/Zellen bekommen, die die Treffer beinhalten, so wie in Access?
Grüße
Alexander
Bitte markiere auch die Kommentare, die zur Lösung des Beitrags beigetragen haben
Content-ID: 151746
Url: https://administrator.de/contentid/151746
Ausgedruckt am: 23.11.2024 um 00:11 Uhr
24 Kommentare
Neuester Kommentar
Hallo Alexander!
Hier mal ein Beispiel, wie so etwas funktionieren könnte, wobei die Suchtreffer in einer MsgBox ausgegeben werden.
Konstanten entsprechend anpassen:
Für Teil-Übereinstimmungen den Parameter xlPart anstatt xlWhole verwenden
Gruß Dieter
[edit] @bastla etwas zu langsam [/edit]
Hier mal ein Beispiel, wie so etwas funktionieren könnte, wobei die Suchtreffer in einer MsgBox ausgegeben werden.
Konstanten entsprechend anpassen:
Const SheetName = "Tabelle1" ' Tabellennamen
Const Suchbereich = "A:C" ' Suchbereich in den Spalten A-C oder in der Art "A:A"
Sub Test()
Dim Suchliste As Variant, Token As Variant, Eingabe As String, Ergebnisliste As String
Eingabe = InputBox("Bitte Suchbegriffe Komma-Getrennt eingeben:", "Suchen...")
If Eingabe = "" Then Exit Sub
Suchliste = Split(Eingabe, ",")
For Each Token In Suchliste
If Token <> "" Then
Call Search(Sheets(SheetName).Range(Suchbereich), Trim(Token), Ergebnisliste)
End If
Next
If Ergebnisliste = "" Then
MsgBox "Keine Übereinstimmung gefunden!", vbInformation, "Suchergebnis..."
Else
MsgBox Ergebnisliste, , "Suchergebnis..."
End If
End Sub
Private Sub Search(ByRef Area, ByRef Token, ByRef List)
Dim Found As Range, FirstAddress As String
Set Found = Area.Find(Token, LookIn:=xlValues, LookAt:=xlWhole, MatchCase:=False)
If Not Found Is Nothing Then
FirstAddress = Found.Address
Do
List = List & Token & vbTab & Found.Address & vbCr
Set Found = Area.FindNext(Found)
Loop While Not Found Is Nothing And Found.Address <> FirstAddress
End If
End Sub
Gruß Dieter
[edit] @bastla etwas zu langsam [/edit]
Hallo nostrakis!
Schematisch könnte das so aussehen:
Grüße
bastla
Schematisch könnte das so aussehen:
Sub Suchen()
Suche = "Haftnotiz Post-It Klebezettel"
QuellTabelle = "Daten"
QuellZeile = 2
SuchSpalte = 2 'B
QuellSpalteVon = 1 'A
QuellSpalteBis = 4 'D
ZielTabelle = "Ergebnis"
ZielZeile = 2
ZielSpalte = "A"
With Worksheets(QuellTabelle)
Wert = .Cells(QuellZeile, SuchSpalte).Value
Do While Wert <> ""
If InStr(1, Suche, Wert, vbTextCompare) > 0 Then
Worksheets(ZielTabelle).Cells(ZielZeile, ZielSpalte).Resize(1, QuellSpalteBis - QuellSpalteVon + 1).Value = .Range(.Cells(QuellZeile, QuellSpalteVon), .Cells(QuellZeile, QuellSpalteBis)).Value
ZielZeile = ZielZeile + 1
End If
QuellZeile = QuellZeile + 1
Wert = .Cells(QuellZeile, SuchSpalte).Value
Loop
End With
End Sub
bastla
Hallo nostrakis!
Grüße
bastla
weil ich trotz der Anpassungen Kompilierungsfehler bekomme
... die der Geheimhaltung unterliegen? Ich speicher das als Modul.
Eigentlich in einem Modul - also "Einfügen" - "Modul" - in das Modul Dieters und / oder meinen Code kopierenFür die Variablen brauche ich dann noch extra Code, oder?
Falls Du damit meinst, dass die Suchbegriffe, die ich in die Variable "Suche" (Zeile 2) geschrieben habe, eingegeben werden sollen, dann ja (wie das gehen könnte, siehst Du in Dieters Beispiel) - ansonsten ist mir die Frage nicht klar ...Sind das Kurzfassungen, die Ihr mir gepostet habt, oder läuft das im Grunde 1:1?
Wenn Du ein Tabellenblatt "Tabelle1" mit Daten in den Spalten A bis C hast, kannst Du Dieters Variante unmittelbar verwenden; für meinen Vorschlag sollten die Tabellen "Daten" und "Ergebnis" existieren (bzw die Tabellennamen in den Zeilen 4 und 10 angepasst werden), wobei in der Spalte B im Blatt "Daten" gesucht wird und die Werte aus den Spalten A bis D der gefundenen Zeilen nach "Ergebnis" übertragen werden.Grüße
bastla
Hallo Alexander!
Wenn der Kompilierungsfehler bei bastlas Code auftritt, dann lösche, falls vorhanden, am Blattanfang die Zeile mit "Option Explicit"
Gruß Dieter
Wenn der Kompilierungsfehler bei bastlas Code auftritt, dann lösche, falls vorhanden, am Blattanfang die Zeile mit "Option Explicit"
Gruß Dieter
Hallo nostrakis!
Um auch Teiilstrings zu finden, müsste jeder einzelne Wert mit allen Suchbegriffen getrennt verglichen werden:
Das Trennzeichen (siehe Zeile 3) zwischen den Suchbegriffen habe ich lt Dieters Beispiel mit Komma vorgegeben, es kann jedoch auch jedes andere nicht in den Suchbegriffen vorkommende Zeichen gewählt werden. Anders als bei Dieters Version (Stichwort: "
Grüße
bastla
P.S.: Im Zweifelsfall würde ich für das Suchen, nicht zuletzt aus Performancegründen, zu Dieters Ansatz raten ...
Um auch Teiilstrings zu finden, müsste jeder einzelne Wert mit allen Suchbegriffen getrennt verglichen werden:
Sub Suchen()
Suche = "Haftnotiz,Post-It,Klebezettel"
Delim = "," 'Trennzeichen zwischen Suchbegriffen
QuellTabelle = "Daten"
QuellZeile = 2
SuchSpalte = "B"
QuellSpalteVon = "A"
QuellSpalteBis = "D"
ZielTabelle = "Ergebnis"
ZielZeile = 2
ZielSpalte = "A"
Such = Split(Suche, Delim) 'Suchbegriffe in Array aufteilen
SuchAnz = UBound(Such) 'höchsten Index des Such-Arrays vor der Schleife (und damit nur einmal) ermitteln
With Worksheets(QuellTabelle)
Wert = .Cells(QuellZeile, SuchSpalte).Value
Do While Wert <> ""
For i = 0 To SuchAnz
If InStr(1, Wert, Such(i), vbTextCompare) > 0 Then
Worksheets(ZielTabelle).Cells(ZielZeile, ZielSpalte).Resize(1, 4).Value = .Range(.Cells(QuellZeile, QuellSpalteVon), .Cells(QuellZeile, QuellSpalteBis)).Value
ZielZeile = ZielZeile + 1
Exit For 'Suchbegriff enthalten, weitere Vergleiche für diesen Wert unnötig
End If
Next
QuellZeile = QuellZeile + 1
Wert = .Cells(QuellZeile, SuchSpalte).Value
Loop
End With
End Sub
LookAt:=xlWhole
") muss bei der Suche nach Teilstrings kein "*" (vor und oder nach dem Suchbegriff) verwendet werden.Grüße
bastla
P.S.: Im Zweifelsfall würde ich für das Suchen, nicht zuletzt aus Performancegründen, zu Dieters Ansatz raten ...
Hallo Alexander, Hallo bastla!
Was spricht eigentlich gegen eine Filterfunktion per ComboBox-Auswahl.
Der AutoFilter läßt nur 2 Kriterien mit Operator (Und/Oder...) zu. Von daher bietet sich eine ComboBox für die Auswahl der Suchbegriffe an, die den AutoFilter je nach Auswahl steuert.
Dazu müsste lediglich im Tabellenblatt eine Combo-Box (ComboBox1) erstellt werden. Den Rest übernimmt der VBA-Code.
Diesen Quellcode zum Initialisieren der ComboBox in "DieseArbeitsmappe" einfügen (Konstanten anpassen):
Und diesen Quellcode in das entsprechende Tabellenblatt (Daten) einfügen (Konstante anpassen):
wobei mit dem Parameter "VisibleDropDown:=False" kein Filter-Steuerelement angezeigt wird.
Der erste Eintrag in der ComboBox wird mit dem Item "Filter Aus" automatisch generiert und die Suchbegriffe in der Konstanten "FilterAuswahl" hinzugefügt.
Einzelne Schritte:
1. Die beiden Quellcodes in ihren Zielort kopieren
2. Eine ComboBox mit dem Namen ComboBox1 erstellen. Bei anderem Namen die Quellcodes entsprechend anpassen.
3. Einmalig Ausführen: Cursor in "DieseArbeitsmappe" auf die Prozedur "Workbook_Open" setzen und die Taste F5 drücken.
Probiers mal aus
Gruß Dieter
Was spricht eigentlich gegen eine Filterfunktion per ComboBox-Auswahl.
Der AutoFilter läßt nur 2 Kriterien mit Operator (Und/Oder...) zu. Von daher bietet sich eine ComboBox für die Auswahl der Suchbegriffe an, die den AutoFilter je nach Auswahl steuert.
Dazu müsste lediglich im Tabellenblatt eine Combo-Box (ComboBox1) erstellt werden. Den Rest übernimmt der VBA-Code.
Diesen Quellcode zum Initialisieren der ComboBox in "DieseArbeitsmappe" einfügen (Konstanten anpassen):
Const FilterSheet = "Tabelle1"
Const FilterAuswahl = "Haftnotiz, Post-It, Klebezettel"
Private Sub Workbook_Open()
Dim Kriterien As Variant, Token As Variant
Kriterien = Split("Filter Aus," & FilterAuswahl, ",")
With Sheets(FilterSheet).ComboBox1
.Clear
For Each Token In Kriterien
If Not Token = "" Then .AddItem Trim(Token)
Next
.ListIndex = 0
End With
End Sub
Const FilterRange = "B:B" 'Spalte mit Filterbegriffen
Private Sub ComboBox1_Change()
Dim Suchtext As String
If ComboBox1.Text = "Filter Aus" Then
ActiveSheet.AutoFilterMode = False
Else
Suchtext = "*" & ComboBox1.Text & "*" 'Teilübereinstimmung vor und nach mit "*"
Range(FilterRange).AutoFilter Field:=1, Criteria1:=Suchtext, VisibleDropDown:=False
End If
End Sub
Der erste Eintrag in der ComboBox wird mit dem Item "Filter Aus" automatisch generiert und die Suchbegriffe in der Konstanten "FilterAuswahl" hinzugefügt.
Einzelne Schritte:
1. Die beiden Quellcodes in ihren Zielort kopieren
2. Eine ComboBox mit dem Namen ComboBox1 erstellen. Bei anderem Namen die Quellcodes entsprechend anpassen.
3. Einmalig Ausführen: Cursor in "DieseArbeitsmappe" auf die Prozedur "Workbook_Open" setzen und die Taste F5 drücken.
Probiers mal aus
Gruß Dieter
Hallo Alexander!
OK, war nur so ne Idee
Gruß Dieter
OK, war nur so ne Idee
Gruß Dieter
Zitat von @midnightautomatic:
Hi Dieter, hi Bastla!
zunächst noch einmal vielen Dank für die Hilfe. Leider ist die Performance der von mir oben genannten kombinierten
Lösung dermaßen schlecht in Excel 2003, dass man sie da nicht mehr verwenden kann.
Und Genau aus diesem Grund hatte bastla ja meine Lösung vorgeschlagen. weil integrierte Excel-Funktionen, wie beispielseise Find/Next codemäßig wesentlich schneller laufen, als MakrocodeHi Dieter, hi Bastla!
zunächst noch einmal vielen Dank für die Hilfe. Leider ist die Performance der von mir oben genannten kombinierten
Lösung dermaßen schlecht in Excel 2003, dass man sie da nicht mehr verwenden kann.
Dieter, wäre es sehr kompliziert, anstatt der Ausgabe in der MsgBox die Ergebnisspalten zeilenweise auf einem Tabellenblatt
auszugeben? Das wäre perfekt.
Nö ist es nicht, ich hatte zu diesem Zeitpunkt nur noch nicht soweit gedacht wie bastla, der schon einen Schritt weiter warauszugeben? Das wäre perfekt.
Meine Konzentration läßt gerade etwas nach und bin von daher im Moment etwas schwer von Begriff Was soll jetzt genau in eine Tabelle geschrieben werden?
Nur die Inhalte aus einer Spalte (vermutlich D) oder ganze Zeilen oder nur die Zell-Adressen oder was?
Gruß Dieter
@Dieter
Grüße
bastla
Und Genau aus diesem Grund hatte bastla ja meine Lösung vorgeschlagen
ich hatte zu diesem Zeitpunkt nur noch nicht soweit gedacht wie bastla, der schon einen Schritt weiter war
I wo - ich weiß einfach, dass Du den besseren VBA-Code schreibst ... ich hatte zu diesem Zeitpunkt nur noch nicht soweit gedacht wie bastla, der schon einen Schritt weiter war
Grüße
bastla
Hallo bastla!
Booaaah, da kann man mal sehen, wieviel ich von Dir gelernt habe
Spaß beiseite! Ich sehe das nicht so, denn Du schaffst es immer wieder, mich mit Deinen faszinierenden Codeschnippsels zu verblüffen
Gruß Dieter
Booaaah, da kann man mal sehen, wieviel ich von Dir gelernt habe
Spaß beiseite! Ich sehe das nicht so, denn Du schaffst es immer wieder, mich mit Deinen faszinierenden Codeschnippsels zu verblüffen
Gruß Dieter
Hallo Alexander!
Teste mal beide Versionen. Ich vermute mal das Version 2 schneller als Version 1 ist?
Version 1:
Version2:
Gruß Dieter
Teste mal beide Versionen. Ich vermute mal das Version 2 schneller als Version 1 ist?
Version 1:
Const SheetQuelle = "Daten" ' Tabelle Daten/Suchen
Const SheetZiel = "Vergleich" ' Tabelle Suchergebnis
Const SpalteSuchen = "C:C" ' Spalte Suchen
Const DatenSpalteVon = "A" ' Daten kopieren von Spalte
Const DatenSpalteBis = "F" ' Daten kopieren bis Spalte
Const ZielSpalte = "A" ' Spalte Ziel-Tabelle
Sub Suchen()
Dim WksQ As Worksheet, WksZ As Worksheet, Suchliste As Variant, Token As Variant, Eingabe As String
Eingabe = InputBox("Bitte Suchbegriffe Komma-Getrennt eingeben:", "Suchliste...")
If Eingabe = "" Then Exit Sub
Set WksQ = Sheets(SheetQuelle)
Set WksZ = Sheets(SheetZiel): WksZ.Cells.Clear
'Überschriftzeile in Ziel-Tabelle schreiben
Range(WksQ.Cells(1, DatenSpalteVon), WksQ.Cells(1, DatenSpalteBis)).Copy WksZ.Cells(1, ZielSpalte)
Suchliste = Split(Eingabe, ",")
For Each Token In Suchliste
If Token <> "" Then Call SearchAndCopy(WksQ, Trim(Token), WksZ)
Next
End Sub
Private Sub SearchAndCopy(ByRef WksQ, ByRef Token, WksZ)
Dim Found As Range, FirstAddress As String, Zeile As Long
With WksQ
Set Found = .Range(SpalteSuchen).Find(Token, LookIn:=xlValues, LookAt:=xlPart, MatchCase:=False)
If Not Found Is Nothing Then
FirstAddress = Found.Address
Do
Zeile = WksZ.Cells(WksZ.Rows.Count, "C").End(xlUp).Row + 1
Range(.Cells(Found.Row, DatenSpalteVon), .Cells(Found.Row, DatenSpalteBis)).Copy _
WksZ.Cells(Zeile, ZielSpalte)
Set Found = .Range(SpalteSuchen).FindNext(Found)
Loop While Not Found Is Nothing And Found.Address <> FirstAddress
End If
End With
End Sub
Const SheetQuelle = "Daten" ' Tabelle Daten/Suchen
Const SheetZiel = "Vergleich" ' Tabelle Suchergebnis
Const SpalteSuchen = "C:C" ' Spalte Suchen
Const DatenSpalteVon = "A" ' Daten kopieren von Spalte
Const DatenSpalteBis = "F" ' Daten kopieren bis Spalte
Const ZielSpalte = "A" ' Spalte Ziel-Tabelle
Sub Suchen()
Dim WksQ As Worksheet, WksZ As Worksheet, Suchliste As Variant, Token As Variant, Eingabe As String
Eingabe = InputBox("Bitte Suchbegriffe Komma-Getrennt eingeben:", "Suchliste...")
If Eingabe = "" Then Exit Sub
Set WksQ = Sheets(SheetQuelle)
Set WksZ = Sheets(SheetZiel): WksZ.Cells.Clear
'Überschriftzeile in Ziel-Tabelle schreiben
Range(WksQ.Cells(1, DatenSpalteVon), WksQ.Cells(1, DatenSpalteBis)).Copy WksZ.Cells(1, ZielSpalte)
Suchliste = Split(Eingabe, ",")
For Each Token In Suchliste
If Token <> "" Then Call SearchAndCopy(WksQ, Trim(Token), WksZ)
Next
End Sub
Private Sub SearchAndCopy(ByRef WksQ, ByRef Token, WksZ)
Dim Found As Range, Suchtext As String, ZeileQ As Long, ZeileZ As Long
With WksQ
Suchtext = "*" & Token & "*" 'Teilübereinstimmung vor und nach mit "*"
If .Range(SpalteSuchen).AutoFilter(Field:=1, Criteria1:=Suchtext, VisibleDropDown:=False) Then
ZeileQ = WksQ.Cells(WksQ.Rows.Count, "C").End(xlUp).Row
ZeileZ = WksZ.Cells(WksZ.Rows.Count, "C").End(xlUp).Row + 1
Range(.Cells(2, DatenSpalteVon), .Cells(ZeileQ, DatenSpalteBis)).Copy WksZ.Cells(ZeileZ, ZielSpalte)
End If
.AutoFilterMode = False
End With
End Sub
Gruß Dieter
Hallo Alexander!
Habs mal getestet
Bei ca 32.000 Zeilen mit 3 Suchbegriffen und 10.000 Treffer-Zeilen dauerts bei mir: Mit Version1 ca 5 Sekunden und mit Version2 weniger als 1 Sekunde. Das sollte an Performance gerade noch akzeptabel sein
Gruß Dieter
Habs mal getestet
Bei ca 32.000 Zeilen mit 3 Suchbegriffen und 10.000 Treffer-Zeilen dauerts bei mir: Mit Version1 ca 5 Sekunden und mit Version2 weniger als 1 Sekunde. Das sollte an Performance gerade noch akzeptabel sein
Gruß Dieter
Hallo,
etwas viel später, aber vlt könnt ihr mir ja helfen. Erstmal Supercode da unten mit der Suche, er funktioniert soweit gut. Allerdings bräuchte ich noch eine Erweiterung. In meiner Tabelle sind mehrere Projekte, der Beginn jedes Projektes ist frablich unterlegt. Jedes Projekt hat gleiche Termin, nur mit unterschiedlichem Datum. Mit der Suche spuckt er mir zwar die Termine aus, aber nicht die Zugehörigkeit zum richtigen Projekt. Kann ich da irgendwas machen, damit das möglich ist? Bin da mit meinem Latein etwas am Ende, und hab keine Idee.
etwas viel später, aber vlt könnt ihr mir ja helfen. Erstmal Supercode da unten mit der Suche, er funktioniert soweit gut. Allerdings bräuchte ich noch eine Erweiterung. In meiner Tabelle sind mehrere Projekte, der Beginn jedes Projektes ist frablich unterlegt. Jedes Projekt hat gleiche Termin, nur mit unterschiedlichem Datum. Mit der Suche spuckt er mir zwar die Termine aus, aber nicht die Zugehörigkeit zum richtigen Projekt. Kann ich da irgendwas machen, damit das möglich ist? Bin da mit meinem Latein etwas am Ende, und hab keine Idee.