Im Beitrag „Abhängige Kombinationsfelder“ (www.access-im-unternehmen.de/****) haben wir beschrieben, wie wir per 1:n-Beziehung verknüpfte Daten in zwei aufeinanderfolgenden Kombinationsfeldern erst filtern und dann auswählen können. Im vorliegenden Beitrag gehen wir einen Schritt weiter und schauen uns an, wie wir abhängige Kombinationsfelder in gebundenen Formularen darstellen. In Formularen in der Einzelansicht gelingt dies ohne Probleme. In der Endlosansicht und der Datenblattansicht stoßen wir jedoch auf Einschränkungen, die wir mehr oder weniger gut umgehen können. Wie das gelingt, lesen Sie ebenfalls in diesem Beitrag.
Datenmodell der Beispieldatenbank
Die Beispieldatenbank erweitert das Modell aus dem ersten Beitrag um eine Ebene.
In tblKategorien stehen die Kategorien, in tblUnterkategorien die Unterkategorien – jede Unterkategorie gehört über den Fremdschlüssel KategorieID zu genau einer Kategorie.
Die Produkte in tblProdukte verweisen mit den beiden Fremdschlüsseln KategorieID und UnterkategorieID zugleich auf ihre Kategorie und ihre Unterkategorie (siehe Bild 1).

Bild 1: Das Datenmodell mit tblKategorien, tblUnterkategorien und tblProdukte
So entstehen zwei gestufte 1:n-Beziehungen, an denen sich das Zusammenspiel gebundener abhängiger Kombinationsfelder gut zeigen lässt.
Außerdem haben wir noch eine 1:n-Beziehung zwischen den Tabellen tblKategorien und tblUnterkategorien hinzugefügt, damit festgelegt ist, welche Unterkategorien zu welcher Kategorie gehören.
Abhängige Kombinationsfelder in gebundenen Formularen
In der Einzelansicht ist die Sache unkompliziert. Als Beispiel dient das Formular frmProdukteDetail, das an die Tabelle tblProdukte gebunden ist und ihre Felder in vier Steuerelementen zeigt (siehe Bild 2): die Textfelder ProduktID und Produkt sowie die beiden Kombinationsfelder cboKategorieID und cboUnterkategorieID, die an die Fremdschlüssel KategorieID und UnterkategorieID gebunden sind. Zum Erstellen dieses Formulars haben wir als Datensatzquelle die Tabelle tblProdukte eingestellt und alle Einträge der Feldliste in den Detailbereich gezogen.

Bild 2: Der Entwurf des Formulars frmProdukteDetail
Als Datensatzherkunft erhält cboKategorieID eine Abfrage über alle Kategorien:
SELECT [tblKategorien].[KategorieID], [tblKategorien].[Kategorie] FROM tblKategorien ORDER BY [Kategorie];
Das abhängige Feld cboUnterkategorieID bekommt zunächst eine Abfrage über sämtliche Unterkategorien als Datensatzherkunft – diese Liste schränken wir gleich per VBA auf die gewählte Kategorie ein.
SELECT [tblUnterkategorien].[UnterkategorieID], [tblUnterkategorien].[Unterkategorie] FROM tblUnterkategorien ORDER BY [Unterkategorie];
Den eigentlichen Mechanismus übernimmt die Ereignisprozedur cboKategorieID_AfterUpdate, die wir für das Ereignis Nach Aktualisierung des Kombinationsfeldes cboKategorieID hinterlegen (siehe Listing 1).
Private Sub cboKategorieID_AfterUpdate() Dim strSQL As String strSQL = "SELECT UnterkategorieID, Unterkategorie FROM tblUnterkategorien WHERE KategorieID = " _ & Me.cboKategorieID & " ORDER BY Unterkategorie" With Me.cboUnterkategorieID .Value = Null .RowSource = strSQL .SetFocus .Dropdown End With End Sub
Listing 1: Die Unterkategorien an die gewählte Kategorie anpassen
Wir stellen eine SELECT-Anweisung zusammen, die nur die Unterkategorien der gewählten Kategorie liefert; das Kriterium bildet der gebundene Wert von cboKategorieID, also die KategorieID. Innerhalb eines With-Blocks setzen wir cboUnterkategorieID zunächst mit Value = Null zurück – so verschwindet eine womöglich noch gespeicherte, nicht mehr passende Unterkategorie -, weisen anschließend die neue Datensatzherkunft zu und klappen die Liste über SetFocus und Dropdown gleich auf.
Das Ergebnis zeigen die beiden folgenden Abbildungen: Bild 3 hält die Auswahl einer Kategorie im Feld cboKategorieID fest.

Bild 3: Auswahl einer Kategorie im Feld cboKategorieID
Unmittelbar nach der Auswahl eines dieser Einträge bietet cboUnterkategorieID nur noch die dazugehörigen Einträge an (siehe Bild 4).

Bild 4: Das gefilterte Kombinationsfeld cboUnterkategorieID nach der Kategorieauswahl
In der Einzelansicht war das – wie versprochen – ohne Hürden. Interessant, und stellenweise widerspenstig, wird es in der Endlos- und der Datenblattansicht; ihnen wenden wir uns im nächsten Abschnitt zu.
Abhängige Kombinationsfelder in gebundenen Endlosformularen
Um die abhängigen Kombinationsfelder in einem Endlosformular zu nutzen, bauen wir das Formular zunächst wie zuvor auf und speichern dieses unter dem Namen frmProdukteEndlos. Hier nutzen wir nun die Anordnen-Funktion von Access.
Wir markieren zunächst alle Steuerleemente des Formulars. Dann wählen wir im Ribbon unter Anordnen den Befehl Tabelle|Tabelle aus. Dies verschiebt die Bezeichnungsfelder in den Formularkopf und belässt die gebundenen Steuerelemente im Detailbereich. Außerdem werden die Steuerelemente tabellarisch wie in Bild 5 angeordnet.

Bild 5: Entwurf des Formulars in der Endlosansicht
Anschließend markieren wir die Anordnung und entfernen diese durch einen Klick auf Tabelle|Layout entfernen.
Außerdem stellen wir für die Eigenschaft Standardansicht den Wert Endlosformular ein.
Für das Ereignis Nach Aktualisierung des Steuerelements cboKategorieID hinterlegen wir wieder die folgende Ereignisprozedur:
Private Sub cboKategorieID_AfterUpdate() Dim strSQL As String strSQL = "SELECT UnterkategorieID, Unterkategorie " _ & "FROM tblUnterkategorien WHERE KategorieID = " _ & Me.cboKategorieID & " ORDER BY Unterkategorie" With Me.cboUnterkategorieID .Value = Null .RowSource = strSQL .SetFocus .Dropdown End With End Sub
Verhalten der abhängigen Kombinationsfelder im Endlosformular
Danach wechseln wir in die Endlosformular-Ansicht und legen einen neuen Datensatz an, für den wir den Produktnamen festlegen. Wir können nun im Feld cboUnterkategorieID noch alle verfügbaren Kategorien auswählen (siehe Bild 6). Für bereits vorhandene Datensätze werden die Unterkategorien noch korrekt angezeigt.
Bild 6: Auswahl der Unterkategorie ohne vorherige Auswahl einer Kategorie
Hier treffen wir keine Auswahl, sondern selektieren zunächst eine Kategorie. Anschließend klappen wir erneut das Kombinationsfeld cboUnterkategorieID auf.
Wie Bild 7 zeigt, hat die Prozedur cboUnterkategorieID_AfterUpdate korrekt funktioniert: Das Kombinationsfeld cboUnterkategorieID zeigt nur noch die zu der gewählten Kategorie gehörenden Unterkategorien an.

Bild 7: Auswahl der Unterkategorie nach vorheriger Auswahl einer Kategorie
Wenn wir eine Unterkategorie ausgewählt haben und den Datensatz verlassen, geschieht jedoch etwas, mit dem wir zunächst nicht gerechnet haben: Das Feld UnterkategorieID wird für alle Datensätze, deren Kategorie nicht der zuletzt gewählten Kategorie entspricht, geleert (siehe Bild 8).
Bild 8: Verschiedene Unterkategorien werden scheinbar willkürlich geleert.
Das Verhalten ändert sich, wenn wir die Kategorie und die Unterkategorie für einen vorhanden Datensatz neu auswählen.
Hier bleiben zunächst alle Einträge im Steuerelement cboUnterkategorieID erhalten. Erst wenn wir einen Datensatz markieren, dessen Kategorie nicht der zuletzt gewählten Kategorie entspricht, wird dessen Feld cboUnterkategorieID geleert.
Der Grund ist in beiden Fällen schnell erläutert: Wir filtern die Datensatzherkunft von cboUnterkategorieID, sodass die anzuzeigenden Werte für die Datensätze mit einer anderen übergeordneten Kategorie nicht mehr verfügbar sind. Dadurch können diese schlicht nicht mehr angezeigt werden.
Tatsächlich sind die gespeicherten Werte für alle Datensätze der Tabelle noch vorhanden, wovon wir uns durch das Schließen und erneute Öffnen des Formulars frmProdukteEndlos überzeugen können (siehe Bild 9).

Bild 9: Nach dem erneuten Öffnen des Formulars sind alle Unterkategorien wieder sichtbar.
Dennoch ist dieses Verhalten äußerst ungünstig, denn wir wollen den Benutzer nicht unnötig verwirren.
Einfache Lösung zum Anzeigen aller Unterkategorien
Unsere Idee zu diesem Problem ist, die Datensatzherkunft des Kombinationsfeldes cboUnterkategorieID nach dem Verlassen des zuletzt bearbeiteten Datensatzes wieder auf die Abfrage einzustellen, die alle Unterkategorien liefert.
Dazu können wir am einfachsten das Ereignis Nach Aktualisierung von cboUnterkategorieID verwenden. Für dieses hinterlegen wir die Ereignisprozedur aus Listing 2.
Private Sub cboUnterkategorieID_AfterUpdate() Dim strSQL As String strSQL = "SELECT UnterkategorieID, Unterkategorie FROM tblUnterkategorien ORDER BY Unterkategorie" With Me.cboUnterkategorieID .RowSource = strSQL End With End Sub
Listing 2: Zurücksetzen der Datensatzherkunft von cboUnterkategorieID
Unser exklusives Angebot für Dich!
(Gilt für den Abschluss eines Jahres-Abonnements im ersten Jahr, danach 189,-/Jahr)
Hier geht’s weiter →Die ersten 4 Wochen kostenlos testen – voller Zugriff auf alle Artikel, vollständigen Code und Beispieldatenbanken. Kein Risiko: Wenn es nicht passt, kündigst Du einfach innerhalb der ersten vier Wochen.
Hast Du eine konkrete Frage zu Deiner eigenen Access-Anwendung?
Vielleicht stellt Deine Anwendung Dich vor eine Herausforderung, zu der Du bisher keine Lösung findest. Schlechte Performance, kein ausreichender Zugriffsschutz, Du bist unsicher über Dein Datenmodell oder Dein Code liefert unerklärliche Fehler?
In unserem kostenlosen Access-Audit schaut sich André Minhorst persönlich gemeinsam mit Dir Deine Lösung per Zoom an – und zeigt Dir, wo Datenmodell, VBA-Code, Ergonomie und Sicherheit Optimierungspotenzial bieten.
Jetzt kostenloses Access-Audit anfordern →