m:n-Daten per Listenfeld filtern

Wenn Sie Daten wie etwa Bestelldaten aus einer m:n-Beziehung in einem Formular verwalten, suchen Sie meist nach Bestellungen eines bestimmten Kunden, mit einem bestimmten Bestelldatum et cetera. Sie könnten aber auch einmal nach solchen Bestellungen suchen, die mindestens einen von mehreren Artikeln enthalten oder die gleich mehrere angegebene Artikel aufführen sollen. Solche eine Suche führen Sie am einfachsten in einem separaten Formular durch, das zur Suche geöffnet wird und die Ergebnisse zur Auswahl bereitstellt.

Die hier vorgestellte Lösung ist auf zwei Formulare aufgeteilt. Das erste Formular entspricht etwa dem von der Nordwind-Datenbank bekannten Bestellformular, das Kundendaten und Bestellinformationen anzeigt (s. Bild 1).

pic001.png

Bild 1: Bestellformular mit Filter-Funktion

Darüber hinaus bietet das Formular mit der Schaltfläche Bestellungen filtern die Möglichkeit, einen weiteren Dialog zu öffnen. Dieser erlaubt es, einen oder mehrere Artikel auszuwählen, nach denen die Bestellungen durchsucht werden. Der Dialog sieht wie in Bild 2 aus und bietet zwei wesentliche Funktionen. Zunächst legen Sie mit einer Optionsgruppe fest, ob Sie Bestellungen mit mindestens einem der nachfolgend angegebenen Artikel anzeigen möchten oder ob die Bestellungen alle gewählten Artikel enthalten müssen. Die Treffer werden gleich im Listenfeld rechts neben den Suchkriterien angezeigt. Mit einem Doppelklick auf einen der gefundenen Einträge zeigen Sie die entsprechende Bestellung im Bestellformular an.

pic002.png

Bild 2: Filterkriterien für Bestellungen zusammenstellen

Formular zur Anzeige der Bestellungen

Dieses Formular enthält keine besonderen Techniken. Das Hauptformular frmBestellungen enthält als Datenherkunft eine Abfrage, die auf der Tabelle tblBestellungen basiert. Das Unterformular sfmBestelldetails liefert die zur jeweiligen Bestellung gehörenden Daten aus der Tabelle tblBestelldetails. Die Schaltfläche cmdOK schließt das Formular, die Schaltfläche cmdBestellungenFiltern öffnet den Dialog zum Zusammenstellen des Filters:

Private Sub cmdBestellungenFiltern_Click()
    DoCmd.OpenForm "frmFilterkriterien"
End Sub

Das Filterformular

Das Formular frmFilterkriterien sieht im Entwurf wie in Bild 3 aus. Zur Eingabe der Filterkriterien stehen zwei Steuerelemente zur Verfügung. Das erste ist die Optionsgruppe ogrArtikelfilter mit den beiden Optionen Oder (Wert 1) und Und (Wert 2) und dem Standardwert 1. Das zweite Steuerelement ist ein Listenfeld namens lstArtikelfilter. Es enthält als Datensatzherkunft den folgenden Ausdruck:

pic003.png

Bild 3: Das Formular frmFilterkriterien in der Entwurfsansicht

SELECT ArtikelID, Artikelname FROM tblArtikel ORDER BY Artikelname;

Dadurch zeigt es alle Artikelnamen in alphabetischer Reihenfolge an. Damit nur die Artikelnamen erscheinen und nicht die ArtikelID, erhalten die beiden Eigenschaften Spaltenanzahl und Spaltenbreiten die Werte 2 und 0cm.

Der Benutzer soll einen oder mehrere Werte dieses Listenfeldes markieren, daher stellen Sie die Eigenschaft Mehrfachauswahl auf Einfach ein (oder Erweitert, je nachdem, was Ihnen angenehmer ist).

Datensatzherkunft des Ergebnislistenfeldes

Das Ergebnislistenfeld zeigt beim Öffnen des Formulars die mit der Abfrage qryBestellungenBestelldetails ermittelten Daten an (s. Bild 4). Diese Abfrage führt Daten aus den Tabellen tblBestellungen, tblBestelldetails und tblArtikel zusammen und sortiert diese aufsteigend nach dem Bestelldatum.

pic004.png

Bild 4: Die Abfrage qryBestellungenBestelldetails dient als Datensatzherkunft des Listenfeldes lstBestellungen.

Auslösen der Aktualisierung der gefundenen Bestellungen

Da es mehr als ein Steuerelement gibt, das die Datensatzherkunft des Listenfeldes lstBestellungen ändert, wurden die Codezeilen zum Filtern der Bestellungen in eine eigene Prozedur ausgegliedert. Diese heißt Bestellungen filtern und wird durch zwei Ereignisse ausgelöst. Das erste ist das Aktualisieren der Optionsgruppe ogrArtikelfilter. Die dazugehörige Ereignisprozedur sieht so aus:

Private Sub ogrArtikelfilter_AfterUpdate()
    BestellungenFiltern
End Sub

Das zweite Ereignis ist das ändern der Auswahl im Listenfeld lstArtikelfilter:

Private Sub lstArtikelfilter_AfterUpdate()
    BestellungenFiltern
End Sub

Gefilterte Bestellungen ermitteln

Die Prozedur BestellungenFiltern im Klassenmodul des Formulars frmFilterkriterien erledigt die Hauptarbeit (s. Listing 1). Die Prozedur durchläuft zunächst alle ausgewählten Einträge des Listenfeldes lstArtikelfilter. Dies geschieht innerhalb einer For…Next-Schleife mit der Laufvariablen i. Die Anzahl der zu durchlaufenden Elemente wird über die Eigenschaft Count der Auflistung ItemsSelected des Listenfeldes ermittelt.

Listing 1: Zusammenstellen der Datensatzherkunft nach dem Festlegen von Filterkriterien

Private Sub BestellungenFiltern()
    Dim i As Integer
    Dim lngIndex As Long
    Dim lngArtikelID As Long
    Dim strFilter As String
    Dim strSQL As String
    Dim intAnzahl As Integer
    For i = 0 To Me!lstArtikelfilter.ItemsSelected.Count - 1
        lngIndex = Me!lstArtikelfilter.ItemsSelected(i)
        lngArtikelID = Me!lstArtikelfilter.ItemData(lngIndex)
        strFilter = strFilter & " OR ArtikelID = " & lngArtikelID
        intAnzahl = intAnzahl + 1
    Next i
    If Len(strFilter) > 0 Then
        strFilter = Mid(strFilter, 4)
        strSQL = "SELECT DISTINCT BestellungID, Bestelldatum, Firma, Kontaktperson " _
            & "FROM qryBestellungenBestelldetails"
        If Me!ogrArtikelfilter = 1 Then
            Me!lstBestellungen.RowSource = strSQL & " WHERE " & strFilter
        Else
            If Not intAnzahl = 0 Then
                strSQL = strSQL & " WHERE (" & strFilter & ") GROUP BY BestellungID, " _
                    & "Bestelldatum, Firma, Kontaktperson HAVING Count(BestellungID)=" _
                    & intAnzahl & ";"
                Me!lstBestellungen.RowSource = strSQL
            End If
        End If
    Else
        Me!lstBestellungen.RowSource = "SELECT DISTINCT BestellungID, Bestelldatum, Firma, " _
            & "Kontaktperson FROM qryBestellungenBestelldetails"
    End If
End Sub

Die erste Zeile innerhalb der Schleife ermittelt den Index des jeweiligen Eintrags der Auflistung ItemsSelected und speichert ihn in der Variablen lngIndex. Wenn beispielsweise als erstes markiertes Element der dritte Eintrag erkannt wird, enthält lngIndex den Wert 2 (die Indizes sind 0-basiert). Die ItemData-Eigenschaft mit diesem Index-Wert als Parameter liefert den Wert der gebundenen Spalte des Listenfeldes, also den Wert des Feldes ArtikelID, und speichert diesen in einer weiteren Variablen namens lngArtikelID. Für jeden markierten Eintrag des Listenfeldes wird nun eine OR-Klausel an die Zeichenkette strFilter angehängt, die etwa wie folgt aussieht:

OR ArtikelID = 12

Außerdem wird die Zählervariable intAnzahl um 1 erhöht. Stellt die Prozedur nach dem Verlassen der For…Next-Schleife fest, dass mindestens ein Eintrag markiert und somit die Länge der in der Variablen strFilter gespeicherten Zeichenkette größer als 0 ist, wird der If-Teil der folgenden If…Then…Else-Bedingung abgearbeitet.

Falls nicht, weist die Prozedur dem Listenfeld lstBestellungen erneut die bereits beim Öffnen des Formulars verwendete Abfrage qryBestellungenBestelldetails als Wert der Eigenschaft RowSource (Datensatzherkunft) zu – mit dem Unterschied, dass nur die vier Felder BestellungID, Bestelldatum, Firma und Kontaktperson ausgegeben werden. Außerdem wird durch Verwendung des Schlüsselworts DISTINCT sichergestellt, dass jede Bestellung nur einmal aufgeführt wird und nicht für jeden Artikel jeweils einmal.

Ist jedoch ein Filterausdruck vorhanden, wird es interessant. Zunächst einmal wird das führende OR mit der Mid-Funktion abgeschnitten, damit aus einem Ausdruck wie

Ende des frei verfügbaren Teil. Wenn Du mehr lesen möchtest, hole Dir ...

den kompletten Artikel im PDF-Format mit Beispieldatenbank

diesen und alle anderen Artikel mit dem Jahresabo

Schreibe einen Kommentar