Home > Artikel > Ausgabe 6/2013 > Filterkriterien für Formulare, Teil III: Kombinationsfelder

Filterkriterien für Formulare, Teil III: Kombinationsfelder

  PDF ansehen

  Download PDF und Beispieldatenbank

In den ersten beiden Teilen dieser Artikelreihe haben Sie erfahren, wie Sie Felder der verschiedenen Datentypen filtern. Nun geht es ans Eingemachte: Wir filtern nach dem Inhalt von Kombinationsfeldern. Eigentlich könnte dies ganz leicht sein: Der Benutzer wählt einfach eine Wert des Kombinationsfeldes aus und die Datenherkunft wird nach dem Wert im entsprechenden Feld gefiltert. Allerdings kann es ja auch geschehen, dass man nicht nach dem Wert des gebundenen Feldes im Kombinationsfeld, sondern nach dem angezeigten Wert filtern möchte. Wir schauen uns beide Fälle an.

Beispieldatenbank

Die Beispiele dieses Artikels finden Sie in der Datenbank 1306_FilterkriterienFuerFormulare.mdb.

Beispielformular

Das Beispielformular sieht wie in Bild 1 aus. Es heißt frmFilternNachKombinationsfeld und enthält im Formularkopf ein Kombinationsfeld namens cboLieferantNachID und ein Textfeld namens txtLieferantNachName.

Formular zum Filtern nach Kombinationsfeldern und ihren Inhalten

Bild 1: Formular zum Filtern nach Kombinationsfeldern und ihren Inhalten

Im Detailbereich haben wir ein Unterformular namens frmFilternNachKombinationsfeld eingerichtet, das die Daten der Tabelle tblArtikel anzeigt.

Filtern nach der gebundenen Spalte

Das Kombinationsfeld cboLieferantNachID soll nach der Auswahl eines Eintrags direkt diejenigen Artikel im Unterformular anzeigen, die vom angegebenen Lieferanten geliefert werden. Dazu muss das Kombinationsfeld allerdings erst einmal alle Lieferanten anzeigen. Diese können Sie auf zwei Arten beziehen:

  • Erstens über die Tabelle tblLieferanten. Dies würde alle Lieferanten liefern, die überhaupt vorhanden sind.
  • Zweitens über eine Abfrage, welche die Tabellen tblArtikel und tblLieferanten verknüpft. Auf diese Weise würde das Kombinationsfeld nur diejenigen Lieferanten anzeigen, die aktuell einem Artikel zugeordnet sind.

Da beide Varianten interessant sind, schauen wir uns beide an. Im ersten Fall weisen Sie der Eigenschaft Datensatzherkunft des Kombinationfeldes die folgende SQL-Anweisung zu:

SELECT LieferantID, Firma

FROM tblLieferanten ORDER BY Firma;

Die Datensätze der Tabelle tblLieferanten werden durch die Klausel ORDER BY Firma direkt nach dem Firmennamen des Lieferanten sortiert.

Damit das Kombinationsfeld nur die Werte des zweiten Feldes anzeigt, aber den Wert aus dem Feld LieferantID aus dem ersten Feld als gebundene Spalte verwendet, stellen Sie noch die beiden folgenden Eigenschaften ein:

  • Spaltenanzahl: 2
  • Spaltenbreiten: 0cm

Das Filtern selbst ist relativ leicht – Sie brauchen nur eine Ereignisprozedur für die Ereigniseigenschaft Nach Aktualisierung des Formulars zu hinterlegen, welche den Filterausdruck des Unterformulars einstellt. Diese Ereignisprozedur finden Sie in Listing 1.

Private Sub cboLieferantNachID_AfterUpdate()

     With Me!sfmFilternNachKombinationsfeld.Form

         .Filter = "LieferantID = " & Me!cboLieferantNachID

         .FilterOn = True

     End With

End Sub

Listing 1: Lieferanten nach ID filtern

Nach der Auswahl eines der Einträge aus dem Kombinationsfeld zeigt das Unterformular nun bereits alle verfügbaren Einträge an (siehe Bild 2).

Filtern von Datensätzen nach der gebundenen Spalte des Nachschlagefeldes

Bild 2: Filtern von Datensätzen nach der gebundenen Spalte des Nachschlagefeldes

Alle Artikel anzeigen

Was aber geschieht, wenn Sie wieder alle Datensätze anzeigen möchten? Das Leeren des Kombinationsfeldes hilft an dieser Stelle nicht weiter. Genau genommen löst dies nach der Aktualisierung des Kombinationfeldes etwa durch Betätigen der Eingabetaste sogar einen Fehler aus – und zwar Fehler 3075, Syntaxfehler (fehlender Operator) in Abfrageausdruck 'LieferantID = '. Da cboLieferantNachID leer ist, stellt die Prozedur also einen ungültigen Ausdruck zusammen. Dies können Sie mit einer einfachen Prüfung umgehen: Sie fragen einfach vor dem Setzen des Filters den Wert des Kombinationfseldes ab. Ist dieser Null, wird der Inhalt durch 0 ersetzt. In diesem Fall leert die neue Version der Prozedur aus Listing 2 den Filter und das Unterformular zeigt wieder alle Datensätze an. Anderenfalls führt das Formular den Filter wie gewohnt aus.

Private Sub cboLieferantNachID_AfterUpdate()

     With Me!sfmFilternNachKombinationsfeld.Form

         If Not Nz(Me!cboLieferantNachID, 0) = 0 Then

             .Filter = "LieferantID = " & Me!cboLieferantNachID

             .FilterOn = True

         Else

             .Filter = ""

         End If

     End With

End Sub

Listing 2: Berücksichtigung eines geleerten Kombinationsfeldes zur Auswahl der Artikel

Eine weitere Alternative ist ein spezieller Eintrag im Kombinationsfeld, der die Bezeichnung aufweist und ebenfalls zum Leeren des Filters führt.

Dieser Wert sollte außerdem als erster Eintrag des Kombinationsfeldes angezeigt werden. Dazu ist ein kleiner Trick nötig, der den Einsatz des UNION-Schlüsselworts erforderlich macht.

Solche Abfragen können Sie nicht über den Abfrageentwurf, sondern nur über die SQL-Ansicht eingeben. Also gehen Sie folgendermaßen vor (im Beispielformular unter cboLieferantNachIDUndAlle zu finden):

  • Markieren Sie die Eigenschaft Datensatzherkunft des Kombinationsfeldes und klicken Sie auf die Schaltfläche mit den drei Punkten.
  • Es erscheint die Entwurfsansicht der Abfrage. Aktivieren Sie nun die SQL-Ansicht (unter Access 2010 beispielsweise wie in Bild 3).
  • Abfrage zur Anzeige eines Eintrags mit dem Text <Alle anzeigen>

    Bild 3: Abfrage zur Anzeige eines Eintrags mit dem Text

  • Ändern den Sie den SQL-Ausdruck wie in der Abbildung.

Der Ausdruck sieht wie folgt aus:

SELECT 0 AS LieferantID,

"" AS Firma

FROM tblLieferanten

UNION

SELECT LieferantID, Firma

FROM tblLieferanten

ORDER BY Firma;

Dieser Ausdruck zeigt die Einträge immer noch nach dem Wert des Feldes Firma sortiert an. Da das Zeichen < vor dem ersten Buchstaben liegt, erscheint der Eintrag als erster Eintrag.

Hier kann es jedoch zu Problemen kommen, die unerfahrene Entwickler möglicherweise nicht lösen können: Wenn Sie beispielsweise den von der Abfrageentwurfsansicht erstellten SQL-Ausdruck einsetzen, werden alle Felder (auch die als Sortierkriterium verwendeten) noch mit vorangestelltem Tabellennamen versehen. Der folgende Ausdruck führt beispielsweise zu einem Fehler:

SELECT 0 AS LieferantID,

"" AS Firma

FROM tblLieferanten

UNION

SELECT tblLieferanten.LieferantID,

tblLieferanten.Firma

FROM tblLieferanten

ORDER BY tblLieferanten.Firma;

Die Fehlermeldung lautet: Der ORDER BY-Ausdruck (tblLieferanten.Firma) enthält Felder, die nicht durch die Abfrage ausgewählt wurden.

Nur die Felder, die in der ersten Abfrage angegeben sind, können in dem ORDER BY-Ausdruck verwendet werden.

Das heißt, dass die Abfrage in der ersten der durch das UNION-Schlüsselwort verbundenen Abfragen ein Feld namens tblLieferanten.Firma erwartet. Also versuchen wir, es Access recht zu machen und ändern den Feldnamen in der ersten Abfrage:

SELECT 0 AS LieferantID,

""

AS tblLieferanten.Firma ...

Dies führt wiederum zu einem Fehler, da es sich bei dem Feldnamen ja um einen Alias-Namen handelt – und der darf nur aus alphanumerischen Zeichen und dem Unterstrich bestehen. Also weichen wir auf die ORDER BY-Klausel aus und entfernen dort den Tabellennamen aus der Feldbezeichnung:

SELECT

...

ORDER BY Firma;

Nun funktioniert es. Nun fehlen noch zwei Dinge: Erstens soll das Kombinationsfeld gleich beim Öffnen des Formulars den ersten Eintrag anzeigen und zweitens benötigen wir auch für dieses Kombinationsfeld eine Ereignisprozedur, die den Filtervorgang durchführt.

Die erste Aufgabe lösen wir mit einem Einzeiler, der gleich beim Laden des Formulars ausgeführt werden soll. Dazu legen Sie zunächst eine Ereignisprozedur für das Ereignis Beim Laden des Formulars an. Ergänzen Sie diese dann wie in Listing 3. Die Prozedur ermittelt mit der Eigenschaft ItemData den Wert der gebundenen Spalte für den Eintrag mit dem Index 0, also für die erste Zeile, und weist diesen Wert als Wert des Kombinationsfeldes zu. Dieses zeigt dann den entsprechenden Eintrag an.

Private Sub Form_Load()

     Me!cboLieferantNachIDUndAlle = Me!cboLieferantNachIDUndAlle.ItemData(0)

End Sub

Listing 3: Anzeigen des ersten Eintrags im Kombinationsfeld gleich beim Öffnen des Formulars

Die Prozedur zum Filtern des Formulars müssen Sie im Vergleich zum vorherigen Beispiel nur geringfügig anpassen – und zwar nur durch das Anlegen einer neuen Ereignisprozedur und das Ändern des Namens des Kombinationsfeldes, welches das Filterkriterium liefert (siehe Listing 4).

Private Sub cboLieferantNachIDUndAlle_AfterUpdate()

     With Me!sfmFilternNachKombinationsfeld.Form

         If Not Nz(Me!cboLieferantNachIDUndAlle, 0) = 0 Then

             .Filter = "LieferantID = " & Me!cboLieferantNachIDUndAlle

             .FilterOn = True

         Else

             .Filter = ""

         End If

     End With

End Sub

Listing 4: Diese Prozedur berücksichtigt auch den Eintrag .

Nur aktuelle Lieferanten anzeigen

Gegebenenfalls enthält die Tabelle tblLieferanten auch Lieferanten, denen überhaupt keine Artikel zugeordnet sind. In diesem Fall würde eine Auswahl eines solchen Lieferanten zu einem leeren Unterformular führen.

Wenn Sie nur solche Lieferanten anzeigen möchten, die auch Artikel liefern, müssen Sie die Basisabfrage zur Ermittlung der Lieferanten anpassen – und zwar so wie in Bild 4.

Abfrage zum Ermitteln aller aktuellen Lieferanten

Bild 4: Abfrage zum Ermitteln aller aktuellen Lieferanten

Dazu ziehen Sie zusätzlich zur Tabelle tblLieferanten noch die Tabelle tblArtikel in den Abfrageentwurf.

Allerdings behalten wir die Ausgabefelder mit LieferantID und Firma bei. Was aber soll dies nun ändern? Ganz einfach: Dadurch, dass Access im Abfrageentwurf automatisch die Beziehung zwischen den beiden Tabellen tblArtikel und tblLieferanten hinzufügt, wirkt sich diese Beziehung auch auf das Abfrageergebnis aus.

In diesem Fall liefert die Abfrage nur solche Datensätze der Tabelle tblLieferanten, für die es auf der anderen Seite des Beziehungspfeils, also in der Tabelle tblArtikel, ebenfalls mindestens einen Datensatz gibt.

Wenn Sie diese Abfrage nun genauso nutzen möchten, wie es beim Kombinationsfeld cboLieferantNachIDUndAlle getan haben, müssen Sie die Datensatzherkunft des Kombinationsfeldes des aktuellen Beispiels (cboLieferantNachIDAktuell) entsprechend anpassen – und zwar so:

SELECT 0 AS LieferantID,

"" AS Firma

FROM tblLieferanten

UNION

SELECT tblLieferanten.LieferantID,

tblLieferanten.Firma

FROM tblLieferanten

INNER JOIN tblArtikel

ON tblLieferanten.LieferantID =

tblArtikel.LieferantID

ORDER BY Firma;

Fertig – das Kombinationsfeld zeigt nur noch die aktuellen Lieferanten an.

Kombinationsfeld nach Inhalt filtern

Kommen wir nun zu einem etwa komplizierten Fall: Der Kunde soll in ein Textfeld eine Zeichenkette eingeben, nach der die im Kombinationsfeld zur Auswahl des Lieferanten im Unterformular enthaltenen Einträge gefiltert werden.

Das heißt, dass bei Eingabe des Buchstaben A etwa alle Artikel angezeigt werden, deren Lieferant mit dem Buchstaben A beginnt.

Das ist nicht so einfach, da das Kombinationsfeld zur Anzeige der Lieferanten im Unterformular die Namen der Lieferanten ja grundsätzlich nur anzeigt, aber diese nicht als Wert enthält. Das Feld LieferantID im Unterformular enthält ja nur die ID des jeweiligen Lieferanten – der Name wird erst über das Nachschlagefeld angezeigt.

Es ist also auch nicht so einfach, den Namen der Lieferanten nach einer vom Benutzer vorgegebenen Zeichenkette zu filtern.

Nun gibt es zwei Ansätze:

  • Sie beziehen das zu untersuchende Feld der verknüpften Tabelle, also das Feld Firma der Tabelle tblLieferanten, bei der Erstellung des Filterkriteriums mit ein.
  • Oder Sie ändern die Datenherkunft des Unterformulars so, dass diese ein zusätzliches Feld namens Firma aus der Tabelle tblLieferanten enthält. Dann können Sie auch ganz einfach, wie im ersten Teil dieser Artikelreihe beschrieben, nach einem Textfeld filtern.

Name in das Filterkriterium einbeziehen

Im ersten Fall benötigen wir schlicht ein etwas komplizierteres Vergleichskriterium.

Dieses setzt die Prozedur aus Listing 5 zusammen und verwendet dabei statt eines herkömmlichen Vergleichswertes die IN-Klausel mit der Angabe einer Unterabfrage.

Private Sub txtLieferantNachName_Change()

     Dim strVergleichswert As String

     Dim strSQL As String

     strVergleichswert = Me!txtLieferantNachName.Text

     If Len(strVergleichswert) > 0 Then

         strSQL = "LieferantID IN (SELECT LieferantID FROM tblLieferanten WHERE Firma LIKE '" & strVergleichswert & "*')"

         With Me!sfmFilternNachKombinationsfeld.Form

             .Filter = strSQL

             .FilterOn = True

         End With

     Else

         Me!sfmFilternNachKombinationsfeld.Form.Filter = ""

     End If

End Sub

Listing 5: Filtern des Unterformulars nach dem Namen des Inhalts eines Nachschlagefeldes

Wie funktioniert das? Nehmen wir die Bestandteile auseinander. Die Unterabfrage lautet folgendermaßen:

SELECT LieferantID FROM tblLieferanten WHERE Firma LIKE '" & strVergleichswert & "*'

Sie liefert also den Wert des Feldes LieferantID für alle Datensätze der Tabelle tblLieferanten, deren Firma mit dem angegebenen Suchausdruck beginnt (beispielsweise A*). Wenn das Ergebnis mehrere Einträge enthält, sieht der als Kriterium verwendete Ausdruck beispielsweise so aus:

LieferantID IN (1,2,3,4)

Dies wiederum zeigt im Unterformular alle Artikel an, deren LieferantID einen der Werte 1, 2, 3 oder 4 enthält.

Anschließend stellt die Prozedur wie gewohnt die Filter-Eigenschaft auf das Kriterium ein und aktiviert den Filter. All dies geschieht jedoch nur, wenn der Benutzer überhaupt ein Zeichen in das Textfeld txtLieferantNachName eingegeben hat – sonst wird der zweite Teil der If...Then-Bedingung ausgeführt, der den Filter zurücksetzt. Dies funktioniert besonders dann, wenn der Benutzer den Inhalt des Suchfeldes leert.

Die zweite Variante, bei der die Datenherkunft des Unterformulars gleich das zu durchsuchende Textfeld enthält, finden Sie in den beiden Formularen frmFilternNachKombinationsfeldII und sfmFilternNachKombinationsfeldII.

Für das Unterformular haben wir eine etwa andere Datenherkunft festgelegt. Statt der Tabelle tblArtikel verwenden wir nun eine Abfrage, welche die beiden Tabellen tblArtikel und tblLieferanten enthält und zusätzlich zu den Feldern der Artikeltabelle noch das Feld Firma in die Datenherkunft einbezieht (siehe Bild 5).

Datenherkunft mit dem Feld Firma als Textfeld

Bild 5: Datenherkunft mit dem Feld Firma als Textfeld

Die Prozedur, die durch das Ändern des Suchbegriffs ausgeführt wird, enthält schließlich ein wesentlich vereinfachtes Kriterium (siehe Listing 6). Dieses vergleicht einfach den Inhalt des Feldes Firma mit dem eingegebenen Suchbegriff plus dem Sternchen (*) als Platzhalter (siehe Bild 6).

Filtern nach dem Lieferantennamen

Bild 6: Filtern nach dem Lieferantennamen

Zusammenfassung und Ausblick

Die Suche nach dem Inhalt von Kombinationsfeldern wäre damit auch abgehakt. In der nächsten Folge der Artikelreihe beschäftigen wir uns schließlich, wie eigentlich bereits für diese Ausgabe angekündigt, mit der Kombination verschiedener Suchkriterien.