Neuigkeiten:

Ist euer Problem gelöst, dann bitte den Knopf "Thema gelöst" drücken!

Mobiles Hauptmenü

Maximale Länge von Me.Filter/Workaround

Begonnen von SeamusQDraide, April 07, 2023, 16:38:18

⏪ vorheriges - nächstes ⏩

SeamusQDraide

Hallo zusammen!

Ich habe folgendes Problem: In einer Datenbank will ich in einem Formular ein Textfeld nach mehreren Werten filtern. Den Filter dafür erstelle ich, indem ich die einzelenen Suchwerte aus einem Listenfeld auslese (der Benutzer kann hier relativ bequem mit Copy/Paste eine Liste einfügen) und sie anschließend über eine For-Schleife zu meinem Filter String zusammenklöppel.
Das sieht ungefähr so aus:
For i = 0 To UBound(Liste) -1
Filterstring = Filterstring & "OR txtFeld = '" & Liste(i) & "'"
Next

Me.Filter = Filterstring

Es funktioniert auch alles prächtig, aber wenn die Länge des Filterstrings über 2048 Zeichen liegt (kommt schneller zusammen, als einem lieb ist), gibt es bei der Zuweisung des Strings zu Me.Filter den Fehler 2176: Die Einstellung dieser Eigenschaft ist zu lang

Soweit ich das verstehe, liegt dies an der Längenbeschränkung von Me.Filter.

Hat jemand einen Tip, wie ich ein Formular alternativ filtern kann? Oder gibt es einen Trick, die Längenbeschränkung zu umgehen?

Vielen Dank für eure Hilfe!
Seamus

PhilS

Mit einer IN-Klausel benötigst du wesentlich weniger Textlänge für dasselbe Ergebnis:

Filterstring = " txtFeld IN ("
For i = 0 To UBound(Liste) -1
   Filterstring = Filterstring & '" & Liste(i) & "',"
Next
Filterstring = Left(Filterstring, Len(Filterstring)-1)  & ")"

Das Kernproblem der limitierten Länge bleibt natürlich weiterhin bestehen. Wenn du komplett unabhängig davon sein willst, kannst du die Werte deiner Liste in eine (temporäre) Tabelle schreiben und die in der Abfrage für dein Form über einen Join einbinden.
Neue Videoserie: Windows API in VBA

Klassische CommandBars visuell bearbeiten: Access DevTools CommandBar Editor

SeamusQDraide

Hallo Phil,

erstmal vielen Dank für die schnelle Antwort!
Leider verstehe ich deine letzte Zeile nicht (ich bin gut in Google, weniger gut in VBA). Was macht die? Kann ich den so generierten Filterstring dann wie gewohnt mit weiteren Filterbedingungen (also & "txtFeld_2 = 'irgendwas'") erweitern und an Me.Filter übergeben?

Viele Grüße
Seamus

MzKlMu

Hallo,
Du kannst auch die Datenherkunft des Formulars neu setzen.
Etwa so:
Dim strSQL As String
strSQL = "Selecct ....." 'bisherige Abfrage
strSQL = strSQL & " Where " & Filterstring
Debug.Print strSQL 'nur zur Kontrolle, diese Zeile und Stop später löschen
Stop 'strsql in den Entwurf einer Abfrage (SQL Sicht) kopieren und Abfrage testen
Me.RecordSource = strSQL
Als Filterstring kannst Du Deine Version verwenden, oder die Version von Phil.
Gruß Klaus

PhilS

Zitat von: SeamusQDraide am April 07, 2023, 18:44:23Leider verstehe ich deine letzte Zeile nicht (ich bin gut in Google, weniger gut in VBA). Was macht die? Kann ich den so generierten Filterstring dann wie gewohnt mit weiteren Filterbedingungen (also & "txtFeld_2 = 'irgendwas'") erweitern und an Me.Filter übergeben?
Die letzte Zeile schneidet das überflüssige Komma am Ende ab und hängt die schließende Klammer an.

Das Ergebnis ist dann sowas:
txtFeld IN ('1','2','3')
Dieses Kriterium kannst du dann beliebig mit weitere Kriterien kombinieren.
Neue Videoserie: Windows API in VBA

Klassische CommandBars visuell bearbeiten: Access DevTools CommandBar Editor

SeamusQDraide

Super, dank dir! Jetzt ist erstmal Urlaub, Ende April schau ich, wie ich weiter komme.

SeamusQDraide

Hallo Klaus,

auch an dich vielen Dank! Ich hab mir das mal angesehen, anscheinend hat auch "Recordsource" eine Obergrenze, die aber wesentlich höher liegt:

Char = "A"
For i = 1 To 32800
Char = Char & "A"
Next
Me.RecordSource = Char

gibt Laufzeitfehler 2176: Eigenschaft zu lang.

Wenn ich bis 32700 iteriere bekomme ich
Laufzeitfehler 2580: Datensatzquelle nicht vorhanden.

>32000 Zeichen sollten für mein Problem ausreichen, zumal mit der IN Anweisung. Ich werde mich nach dem Urlaub mal daran versuchen.

Nochmals vielen Dank und schönes Restostern!
Seamus

SeamusQDraide

#7
So, vielen Dank an alle, die geholfen haben! Damit die Community was davon hat, hier meine aktuelle Lösung, vielleicht hilft sie mal jemand. Ich persönlich find sie ganz elegant:

Option Compare Database

Const srcSQL as String = "Select * FROM qryForm" ' die komplette Datenquelle des Formulars als Modulkonstante. So kann ich jederzeit drauf zugreifen, um die Suchen zurückzusetzen und um mein SQL-statement zu basteln

Der Filter hat drei Komponenten:
-SKrit: Die Liste mit den Eingaben
-Suchfeld: Das zu durchsuchende Feld im Formular
-Suchmodus: Exact oder Substring. Ich wollte den Usern beides anbieten, weil es immer Grüned für das eine und das andere gibt. Insbesondere die "exact" Suche ermöglicht mehr Suchkriterien, weil die IN-Anweisung kompaktter ist, siehe oben. Die Auswahl erfolgt über eine Combobox.

Function FuncORFilterFromList (SKrit As Object, Suchfeld As String, Suchmodus)

FilterStr = "" 'Leeren der Variablen
If Not IsNull(SKrit.ItemData(0)) Then 'leere Listen werden ignoriert

If Suchmodus = "Substring" Then
'Auslesen der Liste und Umbau in Suchstring
For i = 0 To SKrit.ListCount -1
FilterStr = FilterStr & Suchfeld & " LIKE '*" & SKrit.ItemData(i) & "*' OR " 'alle Leerzeichen beachten!
Next
FilterStr = Left(FilterStr, Len(FilterStr) - 4) & ")" 'schneidet das letzte OR ab, um einen korrekten String zu erhalten
End If

If Suchmodus = "Exact" Then
FilterStr = "" & Suchfeld & " IN("
For i = 0 To SKrit.ListCount -1
FilterStr = FilterStr & "'" & SKrit.ItemData(i) & "',"
Next
FilterStr = Left(FilterStr, Len(FilterStr) - 1) & ")"
End If

FuncORFilterFromList = " AND (" & FilterStr & ")" 'Das "AND kommt davor, weil mehrere Felder durchsucht werden sollen. Muss für den Beginn natürlich wieder abgesschintten werden

End If

End Function

Hier dann jetzt der Code für den eigentlichen Filterbutton.
Me.Liste#: Die Listenfelder, in die die User ihre Anfrage eingeben
Suchfeld: Der Name des zu durchsuchenden Formularfelds
cboSerchSuchfeld: Eine Combobox mit den Auswahlmöglichkeiten "Exact" und "Substring"
Das Ergebnis ist ein Filter über mehrere Suchfelder, wobei die Suchfelder mit einem "AND" verknüpft sind, innerhalb der Liste aber eine "OR" Verknüpfung ist:
Also ungefähr so: (Feld1 = Krit1 OR Krit 2) AND (Feld2 = Krit3) --> liefert alle Ergebnisse, wo Feld2 = Krit3 ist UND Feld1 entweder Krit1 ODER Krit2

Public Sub cmdFilter_Click() 'Public, weil ich aus anderen Formularen Werte zum Filtern eingebe und von dort die Filterfunktion aufrufe

'leeren der Variablen
FilterSQL = vbNullString
strSQL = vbNullStrin

Liste1SQL = FuncORFilterFromList(Me.Liste1, "Suchfeld1", cboSearchSuchfeld1)
Liste2SQL = FuncORFilterFromList(Me.Liste2, "Suchfeld2", cboSearchSuchfeld2)
'Hier beliebig viele FElder reinpacken

FilterSQL = Liste1SQL & Liste2SQL

If Not FiterSQL = "" Then 'vermeidet Fehlermeldung, wenn nichts eingegeben wurde
strSQL = Right(FilterSQL, Len(FilterSQL) - 5) 'hier wird das führende "AND" abgeschnitten
FilterSQL = srcSQL & " WHERE " & strSQL
Me.Recordsource = FilterSQL

'Leere Suche:
HitNum = Me.Form.Recordset.Recordcount
If HitNum = 0 Then
MsgBox("Nix gefunden!")
Exit Sub

End If
End If

End Sub

Nochmal vielen Dank an alle, die geholfen haben!