Für Daten mit einer m:n-Beziehung gibt es einige Beispiele: Fahrzeuge und ihre Ausstattungsmerkmale, Artikel und Kategorien, Mitarbeiter und Positionen et cetera. Üblicherweise stellt man diese mit mehreren Steuerelementen dar – etwa die Fahrzeuge im Hauptformular und die Ausstattung im Unterformular. Oder die Mitarbeiter landen im Hauptformular und zwei Listenfelder zeigen die zugeordneten und die nicht zugeordneten Abteilungen an. Was aber, wenn die Daten gar nicht bearbeitet, sondern nur angezeigt werden sollen – und dies möglichst noch in einer einzigen Zeile Dann hilft die Lösung aus diesem Beitrag weiter.
Verknüpfte Daten nebeneinander
Ziel des Beitrags ist es, eine Darstellung wie in Bild 1 zu erhalten. Die ersten paar Spalten sollen die herkömmlichen Felder der m-Tabelle der Verknüpfung liefern. Die folgenden Spalten sollen im Spaltenkopf den Inhalt und die Nummer anzeigen, also etwa Kategorie 1, Kategorie 2 et cetera. Darunter erscheinen schließlich die verknüpften Daten.
Bild 1: Darstellung von per m:n-Beziehung verknüpften Daten in einer Zeile
Beispiel Artikel und Kategorien
Die beiden Tabellen tblArtikel und tblKategorien sind in der Südsturm-Beispieldatenbank eigentlich über das Fremdschlüsselfeld KategorieID der Tabelle tblArtikel verknüpft. Auf diese Weise lässt sich aber nur je eine Kategorie je Artikel festlegen. Was aber, wenn Sie die Kategorien etwas verfeinern möchten und ein Artikel mehreren Kategorien zugeteilt werden soll In diesem Fall benötigen wir eine m:n-Verknüpfungstabelle, die alle denkbaren Kombinationen aus Artikeln und Kategorien speichern kann.
Im Beziehungen-Fenster sieht dies wie in Bild 2 aus; dort können Sie auch erkennen, dass wir das Feld KategorieID aus der Tabelle tblArtikel entfernt haben.
Bild 2: m:n-Beziehung zwischen Artikeln und Kategorien
Die Verknüpfungstabelle tblKategoriezuordnungen enthält drei Felder – das Primärschlüsselfeld sowie zwei Fremdschlüsselfelder, welche beliebige Kombinationen aus den Datensätzen der Tabellen tblArtikel und tblKategorien erlauben. Allerdings schränkt ein zusammengesetzter Index über diese beiden Felder die Werte dahingehend ein, dass jede Kombination aus Artikel und Kategorie nur einmal vorkommen darf.
Dazu legen Sie neben dem Primärindex einen weiteren Index an, der die betroffenen Felder enthält und dessen Eigenschaft Eindeutig auf Ja eingestellt wurde (s. Bild 3).
Bild 3: Jede Kombination aus Artikel und Kategorie ist nur einmal möglich.
Sie können nun wie in Bild 4 einige Beispieldatensätze für die Zuordnung von Artikeln zu Kategorien hinzufügen.
Bild 4: Beispieldatensätze für die m:n-Beziehung
Liste per VBA erzeugen
Nun könnten Sie jedem Artikel per VBA eine entsprechende Liste der Kategorien hinzufügen – diese müsste jedoch regelmäßig aktualisiert werden. Die Liste soll in der Tabelle tblArtikel in einem weiteren Feld namens Kategorien gespeichert werden. Die VBA-Prozedur zum Füllen dieses Feldes sieht wie in Listing 1 aus.
Listing 1: Zusammenstellen der Kategorienliste per VBA
Public Sub KategorielisteSchreiben() Dim db As DAO.Database Dim rstArtikel As DAO.Recordset Dim rstKategorien As DAO.Recordset Dim strKategorien As String Set db = CurrentDb Set rstArtikel = db.OpenRecordset("SELECT * FROM tblArtikel", dbOpenDynaset) Do While Not rstArtikel.EOF strKategorien = "" Set rstKategorien = db.OpenRecordset("SELECT t2.Kategoriename FROM" _ & "tblKategoriezuordnungen AS t1 INNER JOIN tblKategorien AS t2 ON t1.KategorieID = " _ & "t2.KategorieID WHERE t1.ArtikelID = " & rstArtikel!ArtikelID, dbOpenDynaset) Do While Not rstKategorien.EOF strKategorien = strKategorien & ";" & rstKategorien!Kategoriename rstKategorien.MoveNext Loop If Len(strKategorien) > 0 Then strKategorien = Mid(strKategorien, 2) End If With rstArtikel .Edit !Kategorien = strKategorien .Update End With rstArtikel.MoveNext Loop Set db = Nothing End Sub
Die Prozedur legen Sie in einem beliebigen Standardmodul an und starten diese nach dem Platzieren der Einfügemarke innerhalb der Prozedur mit der Taste F5.
Wenn Sie die Prozedur beispielsweise immer dann verwenden wollen, bevor die Artikeldaten in einem Formular angezeigt werden, rufen Sie es in der Ereignisprozedur auf, die durch das Ereignis Beim Laden des Formulars ausgelöst wird.
Die Prozedur selbst ist die einfachste Variante, um zum gewünschten Ergebnis zu kommen. Allerdings birgt das Ergebnis auch den Nachteil redundanter Daten in sich. Sobald einer der Artikel einer weiteren Kategorie zugeordnet wird oder eine Zuordnung entfällt, stimmen die Daten im Feld Kategorien nicht mehr.
Die Prozedur erstellt zunächst ein Recordset auf Basis der Tabelle tblArtikel. Per Do While durchläuft die Prozedur alle Datensätze der Tabelle tblArtikel in einer äußeren Schleife.
Innerhalb dieser Schleife erzeugt die Prozedur eine weitere Datensatzgruppe, die diesmal alle Datensätze der verknüpften Tabellen tblKategoriezuordnungen und tblKategorien enthält, bei denen das Feld ArtikelID mit der ID des aktuell in der äußeren Schleife bearbeiteten Artikel-Datensatzes übereinstimmt. Auch die Datensätze dieses Recordsets werden innerhalb einer Do While-Schleife durchlaufen. Dabei stellt die Prozedur in der Stringvariablen strKategorien eine per Semikola getrennte Liste der Kategorienamen zusammen.
Dabei wird mit jedem Durchlauf ein Ausdruck wie ;<Kategoriename> zur Zeichenkette in strKategorien hinzugefügt. Sollte diese zumindest eine Kategorie enthalten, muss natürlich noch das führende Semikolon entfernt werden, was eine entsprechende Anweisung mit der Mid-Funktion erledigt.
Schließlich trägt die Prozedur die Kategorienliste in das Feld Kategorien des aktuellen Datensatzes des Recordsets rstArtikel ein.
Das Ergebnis können Sie in Bild 5 begutachten. Alle Datensätze der Tabelle tblArtikel enthalten im Feld Kategorien einen oder mehrere durch Semikola getrennte Kategorienamen.
Bild 5: Tabelle mit der Kategorienliste im Feld Kategorien