{"id":55001587,"date":"2026-02-01T00:00:00","date_gmt":"2026-02-06T13:37:56","guid":{"rendered":"http:\/\/access-im-unternehmen.aix-dev.de\/aiu\/?p=1587"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-30T00:00:00","slug":"Reflexive_1nBeziehung_zu_mnBeziehung","status":"publish","type":"post","link":"https:\/\/access-im-unternehmen.de\/Reflexive_1nBeziehung_zu_mnBeziehung\/","title":{"rendered":"Reflexive 1:n-Beziehung zu m:n-Beziehung"},"content":{"rendered":"<p><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/vg01.met.vgwort.de\/na\/7bf4cb1679ba4ea685ab6870b1c08061\" width=\"1\" height=\"1\" alt=\"\"><b>Manchmal legt man eine 1:n-Beziehung zwischen zwei Tabellen an, um sp&auml;ter festzustellen, dass eine m:n-Beziehung doch die funktionalere Variante ist. Ein Beispiel sind reflexive Beziehungen, mit denen man etwa Vater-Kind-Beziehungen abbildet oder Partner-Beziehungen. Andere Beispiele sind solche wie zwischen Produkten und Kategorien &#8211; man dachte zun&auml;chst, dass es reicht, wenn man jedes Produkt nur einer Kategorie zuordnen kann, aber man dann erkennt, dass es f&uuml;r verschiedene Anwendungsf&auml;lle doch g&uuml;nstiger w&auml;re, wenn man ein Produkt mehr als einer Kategorie zuordnen kann. &Auml;hnliche F&auml;lle sind Mitarbeiter und Funktionen oder Abteilungen. In diesem Beitrag schauen wir uns das Beispiel eines Kunden an, der in seinem Sportverein partnerschaftliche Beziehungen &uuml;ber ein Fremdschl&uuml;sselfeld der Tabelle tblMitglieder auf diese selbst abgebildet hat. Hier gab es mehrere Gr&uuml;nde, um diese Beziehung in eine m:n-Beziehung umzuwandeln. Welche das sind und wie wir die Umwandlung durchgef&uuml;hrt haben, lesen Sie in diesem Beitrag.<\/b><\/p>\n<p>Das Abbilden von reflexiven Beziehungen &uuml;ber eine 1:n-Beziehung ist an sich nicht falsch. Im Beispiel geht es um einen Sportverein, dessen Mitglieder mit einer Access-Datenbank verwaltet werden. In der Tabelle tblMitglieder gibt es zwei Felder, um die partnerschaftliche Beziehung zwischen zwei Mitgliedern abzubilden. Das erste hei&szlig;t <b>PartnerID <\/b>und dient dazu, die ID eines anderen Datensatzes dieser Tabelle zu referenzieren und damit anzugeben, welches andere Mitglied mit diesem Mitglied verbunden ist. Zus&auml;tzlich gibt es ein <b>Ja\/Nein<\/b>-Feld namens <b>Ehepartner<\/b>, das angibt, ob es sich um eine amtlich dokumentierte Beziehung handelt, sprich um eine eheliche Beziehung (<b>Ja<\/b>) oder um eine Beziehung ohne Trauschein (<b>Nein<\/b>). Der Entwurf der Tabelle sieht in abgespeckter Form wie in Bild 1 aus.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2026_01\/pic_1587_001.png\" alt=\"Entwurf der Tabelle tblMitglieder\" width=\"499,5589\" height=\"360,515\"\/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 1: Entwurf der Tabelle tblMitglieder<\/span><\/b><\/p>\n<p>Das erste Problem, das sich daraus ergibt, ist die wechselseitige Abh&auml;ngigkeit. Wenn wir f&uuml;r Mitglied A das Mitglied B als Partner festgelegt haben, m&uuml;ssen wir f&uuml;r Mitglied B auch Mitglied A als Partner hinterlegen &#8211; und f&uuml;r beide muss das Feld <b>Ehepartner<\/b> den gleichen Wert enthalten. Anderenfalls erhalten wir einen Fall von inkonsistenten Daten.<\/p>\n<p>Diese Inkonsistenz kann nicht nur den Fall enthalten, dass die Beziehung nur in einer Richtung dokumentiert ist, etwa von Mitglied A zu Mitglied B. Es kann auch passieren, dass nicht nur Mitglied B als Partner von Mitglied A angegeben wird, sondern auch noch Mitglied C als Partner von Mitglied B. Es konnte auch vorkommen, dass ein Mitglied als Ehepartner von mehreren anderen Mitgliedern angegeben wird.<\/p>\n<p>Das zweite Problem bei der Tabelle <b>tblMitglieder <\/b>bei diesem Kunden war, dass bereits sehr viele andere Tabellen auf die Tabelle <b>tblMitglieder <\/b>verwiesen hatten und somit die Grenze von maximal 32 Beziehungen erreicht war.<\/p>\n<p>Diese Grenze gilt f&uuml;r Beziehungen, die &uuml;ber ein Fremdschl&uuml;sselfeld in dieser Tabelle hergestellt werden, wobei wir hier sehr viele Lookup-Tabellen vorgefunden haben.<\/p>\n<p>Die Beziehung war wie in Bild 2 aufgebaut, wobei das Fremdschl&uuml;sselfeld <b>PartnerID <\/b>auf das Feld <b>MitgliedID <\/b>der gleichen Tabelle verweist.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2026_01\/pic_1587_002.png\" alt=\"Reflexive Beziehung der Mitglieder\" width=\"424,5589\" height=\"297,9361\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 2: Reflexive Beziehung der Mitglieder<\/span><\/b><\/p>\n<h2>Mehrere Partner f&uuml;r das gleiche Mitglied verhindern<\/h2>\n<p>Die M&ouml;glichkeit, dass ein Mitglied f&uuml;r mehr als ein anderes Mitglied als Partner ausgew&auml;hlt wird, konnten wir durch das Setzen eines eindeutigen Schl&uuml;ssels f&uuml;r das Fremdschl&uuml;sselfeld <b>PartnerID <\/b>erreichen.<\/p>\n<p>Dadurch, dass nun jede <b>MitgliedID <\/b>nur einmal in das Feld <b>PartnerID <\/b>eingetragen werden konnte, stellen wir sicher, dass es nur monogame Beziehungen gibt. Hier lassen wir au&szlig;en vor, dass es Kulturen gibt, in denen dies m&ouml;glich ist.<\/p>\n<h2>Auswahl einer Beziehung mit sich selbst verhindern<\/h2>\n<p>Eine weitere m&ouml;gliche Fehleingabe ist die Auswahl des Mitglieds selbst als Partner.<\/p>\n<p>Dies k&ouml;nnen wir verhindern, indem wir im Formular, das wir gleich beschreiben, nur die anderen Datens&auml;tze der Tabelle <b>tblMitglieder <\/b>anzeigen.<\/p>\n<h2>Nur eindeutige Partnerschaften erlauben<\/h2>\n<p>Wenn wir sicherstellen wollen, dass die in einer Partnerschaft befindlichen Mitglieder immer wechselseitig miteinander verbunden werden, m&uuml;ssen wir das &uuml;ber die Anwendungslogik realisieren &#8211; allein &uuml;ber den Tabellenentwurf k&ouml;nnen wir das mit einem Fremdschl&uuml;sselfeld, das die gleiche Tabelle referenziert, nicht erreichen.<\/p>\n<p>Wir m&uuml;ssen also im Formular zum Verwalten der Mitglieder eine VBA-Funktion einbauen, die beim Ausw&auml;hlen des Partners eines Mitglieds automatisch auch das Feld PartnerID des Partners einstellt &#8211; und die auch den gleichen Wert im <b>Ja\/Nein<\/b>-Feld <b>Ehepaar <\/b>f&uuml;r die verkn&uuml;pften Datens&auml;tze festlegt.<\/p>\n<p>Im Entwurf der Tabelle <b>tblMitglieder <\/b>haben wir f&uuml;r das Fremdschl&uuml;sselfeld <b>PartnerID <\/b>ein Nachschlagefeld definiert, damit man den Partner einfach ausw&auml;hlen kann (siehe Bild 3).<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2026_01\/pic_1587_003.png\" alt=\"Auswahlfeld f&uuml;r den Partner\" width=\"549,559\" height=\"241,052\"\/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 3: Auswahlfeld f&uuml;r den Partner<\/span><\/b><\/p>\n<h2>Formular zum Verwalten der Mitglieder und Partnerschaften<\/h2>\n<p>Um die Mitglieder zu verwalten und die Partner zuordnen zu k&ouml;nnen, haben wir ein Formular wie in Bild 4 vorgefunden.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2026_01\/pic_1587_004.png\" alt=\"Formular zur Mitgliederverwaltung\" width=\"424,5589\" height=\"236,4868\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 4: Formular zur Mitgliederverwaltung<\/span><\/b><\/p>\n<p>F&uuml;r das Steuerelement <b>cboPartnerID <\/b>haben wir zun&auml;chst die folgende Datensatzherkunft eingestellt, um aus allen Mitgliedern ausw&auml;hlen zu k&ouml;nnen:<\/p>\n<pre>SELECT MitgliedID, Vorname & '' '' & Nachname FROM tblMitglieder<\/pre>\n<p>Damit beim Anzeigen eines Datensatzes nicht das aktuelle Mitglied selbst erscheint und auch nicht solche Mitglieder, die bereits einer Partnerschaft zugeordnet sind, haben wir f&uuml;r das Ereignis <b>Beim Anzeigen <\/b>die folgende Prozedur hinterlegt:<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>Form_Current()\r\n     Me.cboPartnerID.RowSource = \"SELECT MitgliedID, \" _\r\n         & \"Vorname & '' '' & Nachname FROM tblMitglieder \" _\r\n         & \"WHERE NOT (MitgliedID = \" & Me.MitgliedID & \") \" _\r\n         & \" AND (MitgliedID NOT IN (\" _\r\n         & \"    SELECT PartnerID FROM tblMitglieder \" _\r\n         & \"    WHERE PartnerID IS NOT NULL))\"\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>F&uuml;r das Mitglied mit dem Wert <b>1 <\/b>im Feld <b>MitgliedID <\/b>erhalten wir so die folgende Abfrage:<\/p>\n<pre>SELECT MitgliedID, Vorname & '' '' & Nachname \r\nFROM tblMitglieder \r\nWHERE NOT (MitgliedID = 1) \r\nAND (MitgliedID NOT IN (\r\n     SELECT PartnerID FROM tblMitglieder \r\n     WHERE PartnerID IS NOT NULL)\r\n)<\/pre>\n<p>Damit erscheinen, wenn wir noch keinem Mitglied einen Partner zugewiesen haben, f&uuml;r jedes Mitglied nur die aktuell verf&uuml;gbaren Partner im Feld <b>cboPartnerID<\/b> &#8211; siehe Bild 5.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2026_01\/pic_1587_005.png\" alt=\"Formular zur Mitgliederverwaltung in der Formularansicht\" width=\"424,5589\" height=\"236,4868\"\/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 5: Formular zur Mitgliederverwaltung in der Formularansicht<\/span><\/b><\/p>\n<h2>Partnerschaft f&uuml;r den Partner einstellen<\/h2>\n<p>Wenn wir nun f&uuml;r das Mitglied mit dem Wert <b>1 <\/b>im Feld <b>MitgliedID <\/b>einen Partner ausw&auml;hlen, etwa den mit dem Wert <b>2<\/b>, soll f&uuml;r das Mitglied <b>2 <\/b>das Mitglied <b>1 <\/b>als Partner eingestellt werden.<\/p>\n<p>Dazu hinterlegen wir f&uuml;r das Ereignis <b>Nach Aktualisierung <\/b>des Kombinationsfeldes <b>cboPartnerID <\/b>die folgende Prozedur:<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>cboPartnerID_AfterUpdate()\r\n     <span style=\"color:blue;\">Dim <\/span>db<span style=\"color:blue;\"> As <\/span>DAO.Database\r\n     <span style=\"color:blue;\">Set<\/span> db = CurrentDb\r\n     db.Execute \"UPDATE tblMitglieder SET PartnerID = \" _\r\n         & Me.MitgliedID & \" WHERE MitgliedID = \" _\r\n         & Me.cboPartnerID, dbFailOnError\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Die so ausgef&uuml;hrte Aktionsabfrage lautet beispielsweise:<\/p>\n<pre>UPDATE tblMitglieder SET PartnerID = 1 WHERE MitgliedID = 2<\/pre>\n<p>Damit erhalten wir das gew&uuml;nschte Ergebnis in der zugrunde liegenden Tabelle, aber wenn wir zum Datensatz des gew&auml;hlten Partners wechseln und dann zur&uuml;ck, zeigt das Kombinationsfeld nun f&uuml;r beide gar keinen Wert mehr an. Das liegt daran, dass wir die bereits vergebenen Partner vollst&auml;ndig ausschlie&szlig;en und diese somit auch f&uuml;r den ausgew&auml;hlten Eintrag nicht mehr angezeigt werden. Das Kombinationsfeld enth&auml;lt zwar den korrekten Eintrag, was wir im Direktbereich mit folgender Anweisung ermitteln k&ouml;nnen:<\/p>\n<pre>  Screen.ActiveControl.Value\r\n  2 <\/pre>\n<p>Aber da der Eintrag nicht in der Datensatzherkunft des Kombinationsfeldes enthalten ist, erscheint der Anzeigewert nicht.<\/p>\n<p>Wir m&uuml;ssen die Datensatzherkunft also nochmals anpassen, indem wir mit der <b>OR<\/b>-Klausel am Ende den gew&auml;hlten Partner wieder mit in die Auswahl hineinnehmen &#8211; hier der besseren Lesbarkeit halber direkt mit den Werten <b>1 <\/b>f&uuml;r <b>MitgliedID <\/b>und <b>2 <\/b>f&uuml;r <b>PartnerID<\/b>:<\/p>\n<pre>SELECT MitgliedID, Vorname & '' '' & Nachname \r\nFROM tblMitglieder \r\nWHERE NOT (MitgliedID = 1) AND (MitgliedID NOT IN (\r\n     SELECT PartnerID FROM tblMitglieder \r\n     WHERE PartnerID IS NOT NULL) \r\nOR MitgliedID = 2)<\/pre>\n<p>Damit sehen wir nun den ausgew&auml;hlten Partner sowohl f&uuml;r den ersten als auch f&uuml;r den zweiten Datensatz. In der <b>OR<\/b>-Bedingung sorgen wir au&szlig;erdem mit der <b>Nz<\/b>-Funktion daf&uuml;r, dass im Falle des Wertes <b>NULL <\/b>im Feld <b>PartnerID <\/b>der Wert <b>0 <\/b>verwendet wird &#8211; sonst erhalten wir beim Wechsel von einem Datensatz ohne <b>PartnerID <\/b>zu einem anderen Datensatz einen Fehler.<\/p>\n<p>Schlie&szlig;lich m&uuml;ssen wir auch noch daf&uuml;r sorgen, dass der Wert f&uuml;r das Feld <b>Ehepaar <\/b>f&uuml;r das als Partner angegebene Mitglied so einstellen wie f&uuml;r das Mitglied selbst. Dazu f&uuml;gen wir eine Prozedur f&uuml;r das Ereignis <b>Nach Aktualisierung <\/b>des Kontrollk&auml;stchens <b>chkEhepaar <\/b>hinzu:<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>chkEhepaar_AfterUpdate()\r\n     <span style=\"color:blue;\">Dim <\/span>db<span style=\"color:blue;\"> As <\/span>DAO.Database\r\n     <span style=\"color:blue;\">Set<\/span> db = CurrentDb\r\n     db.Execute \"UPDATE tblMitglieder SET Ehepaar = \" _\r\n         & IIf(Me.chkEhepaar = True, \"True\", \"False\") _\r\n         & \" WHERE MitgliedID = \" & Me.cboPartnerID, _\r\n         dbFailOnError\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<h2>Warum auf m:n-Beziehung umstellen?<\/h2>\n<p>Eingangs haben wir erw&auml;hnt, dass sich viele der hier beschriebenen Probleme beheben lassen, wenn wir die reflexive Beziehung &uuml;ber die 1:n-Verkn&uuml;pfung aufheben, die Felder <b>PartnerID <\/b>und <b>Ehepaar <\/b>entfernen und beides in eine m:n-Beziehung auslagern.<\/p>\n<p>Wir schauen uns erst einmal an, wie die Verkn&uuml;pfungstabelle aussieht und wie wir diese mit der Tabelle <b>tblMitglieder <\/b>verkn&uuml;pfen. Damit das Beispiel mit der reflexiven 1:n-Beziehung erhalten bleibt, erstellen wir in der Beispieldatenbank eine Kopie der Tabelle <b>tblMitglieder <\/b>(siehe Bild 6) unter dem Namen <b>tblMitgliederMN<\/b>. Au&szlig;erdem f&uuml;gen wir die Tabelle <b>tblPartnerschaften <\/b>hinzu, die folgende Felder enth&auml;lt:<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2026_01\/pic_1587_006.png\" alt=\"Aktueller Zustand der Daten in der Tabelle tblMitglieder\" width=\"424,5589\" height=\"191,588\"\/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 6: Aktueller Zustand der Daten in der Tabelle tblMitglieder<\/span><\/b><\/p>\n<ul>\n<li><b>PartnerschaftID<\/b>: Prim&auml;rschl&uuml;sselfeld der Tabelle<\/li>\n<li><b>PartnerA<\/b>: Erster Partner, Fremdschl&uuml;sselfeld zur Tabelle <b>tblMitglieder<\/b>, eindeutiger Index, Eingabe erforderlich<\/li>\n<li><b>PartnerB<\/b>: Zweiter Partner, Fremdschl&uuml;sselfeld zur Tabelle <b>tblMitglieder<\/b>, eindeutiger Index, Eingabe erforderlich<\/li>\n<li><b>Ehepaar<\/b>: <b>Ja\/Nein<\/b>-Feld, das angibt, ob es sich um ein Ehepaar handelt<\/li>\n<\/ul>\n<p>Dadurch, dass wir einen eindeutigen Index auf die Felder <b>PartnerA <\/b>und <b>PartnerB <\/b>legen, stellen wir sicher, dass jedes Mitglied nur einmal als PartnerA oder PartnerB angegeben werden kann.<\/p>\n<p>Wir haben allerdings noch eine kleine L&uuml;cke: Wir k&ouml;nnen die Kombination aus Mitglied <b>1 <\/b>und Mitglied <b>2 <\/b>immer noch zweimal angeben &#8211; einmal mit dem Wert <b>1 <\/b>im Feld <b>PartnerA <\/b>und <b>2 <\/b>in <b>PartnerB <\/b>und umgekehrt. Au&szlig;erdem k&ouml;nnen wir theoretisch auch Mitglied <b>1 <\/b>sowohl in das Feld <b>PartnerA <\/b>als auch in <b>PartnerB <\/b>eingeben.<\/p>\n<p>Dies verhindern wir, indem wir f&uuml;r die Tabelle eine G&uuml;ltigkeitsregel anlegen, die wir wie in Bild 7 definieren.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2026_01\/pic_1587_007.png\" alt=\"Tabelle tblPartnerschaften\" width=\"499,5589\" height=\"456,3766\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 7: Tabelle tblPartnerschaften<\/span><\/b><\/p>\n<p>Wenn wir nun eine Partnerschaft eingeben, bei welcher der Wert von <b>PartnerA <\/b>kleiner oder gleich der von <b>PartnerB <\/b>ist, erhalten wir die Meldung aus Bild 8.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2026_01\/pic_1587_008.png\" alt=\"Meldung beim Eingeben ung&uuml;ltiger Daten\" width=\"499,5589\" height=\"393,7044\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 8: Meldung beim Eingeben ung&uuml;ltiger Daten<\/span><\/b><\/p>\n<p>Diese Regel ist nur f&uuml;r den Fall vorgesehen, dass jemand versucht, Daten direkt &uuml;ber die Tabelle einzugeben. Das eigentliche Anlegen erledigen wir ohnehin &uuml;ber das Formular.<\/p>\n<h2>Beziehung zwischen Mitgliedern und Partnerschaften<\/h2>\n<p>Damit nur Werte aus dem Prim&auml;rschl&uuml;sselfeld der Tabelle <b>tblMitglieder <\/b>eingegeben werden k&ouml;nnen, f&uuml;gen wir dem Datenmodell die beiden Beziehungen aus Bild 9 hinzu.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2026_01\/02-01-2026_16-04-39.png\" alt=\"Beziehungen f&uuml;r die Verwaltung von Partnerschaften per m:n-Beziehung\" width=\"649,559\" height=\"438,6876\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 9: Beziehungen f&uuml;r die Verwaltung von Partnerschaften per m:n-Beziehung<\/span><\/b><\/p>\n<p>Wichtig ist hier die Richtung, in der wir die Beziehungspfeile ziehen. Da die beiden Felder <b>PartnerA <\/b>und <b>PartnerB <\/b>mit einem eindeutigen Index versehen wurden, m&uuml;ssen wir den Pfeil von <b>tblMitglieder <\/b>auf <b>tblPartnerschaften <\/b>ziehen, sodass die Mitgliedertabelle unter <b>Tabelle\/Abfrage <\/b>und die Partnerschaftstabelle unter <b>Verwandte Tabelle\/Abfrage <\/b>angegeben wird.<\/p>\n<p>Andersherum k&ouml;nnten wir keine referenzielle Integrit&auml;t f&uuml;r die Beziehungen festlegen, da dann das Feld <b>MitgliedID <\/b>der Tabelle <b>tblMitglieder <\/b>als Fremdschl&uuml;sselfeld betrachtet w&uuml;rde und es darin Werte gibt, die zurzeit noch nicht im Feld <b>PartnerA <\/b>oder <b>PartnerB <\/b>der Tabelle <b>tblPartnerschaften <\/b>enthalten sind.<\/p>\n<h2>Daten migrieren<\/h2>\n<p>Es gibt bereits eingetragene Partnerschaften in der Tabelle <b>tblMitarbeiterMN<\/b>, die wir nun &uuml;ber die Verkn&uuml;pfungstabelle <b>tblPartnerschaften <\/b>abbilden wollen.<\/p>\n<p>Das ist anspruchsvoll, weil wir die Partnerschaften so eintragen m&uuml;ssen, dass der Wert im Feld <b>PartnerA <\/b>immer kleiner als der in <b>PartnerB <\/b>ist. Wir k&ouml;nnten starten, indem wir die Partnerschaften aufsteigend nach der ID des Mitglieds sortieren und zus&auml;tzlich die <b>PartnerID<\/b> und den <b>Ehepaar<\/b>-Status mit folgender Abfrage ausgeben lassen:<\/p>\n<pre>SELECT\r\n     tblMitgliederMN.MitgliedID,\r\n     tblMitgliederMN.PartnerID,\r\n     tblMitgliederMN.Ehepaar\r\nFROM\r\n     tblMitgliederMN\r\nWHERE\r\n     (((tblMitgliederMN.PartnerID) IS NOT NULL))\r\nORDER BY\r\n     tblMitgliederMN.MitgliedID;<\/pre>\n<p>Dies liefert jede Partnerschaft in doppelter Ausf&uuml;hrung, jeweils einmal mit jeder Mitglieds-ID im Feld <b>MitgliedID <\/b>und einmal im Feld <b>PartnerID <\/b>(siehe Bild 10).<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2026_01\/pic_1587_009.png\" alt=\"Ausgabe aller Partnerschaften laut tblMitgliederMN\" width=\"424,5589\" height=\"179,4527\"\/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 10: Ausgabe aller Partnerschaften laut tblMitgliederMN<\/span><\/b><\/p>\n<p>Wenn wir hier allerdings den Ausdruck, den wir als G&uuml;ltigkeitsregel f&uuml;r die Tabelle <b>tblPartnerschaften <\/b>verwendet haben, als Kriterium einsetzen, erhalten wir jede Partnerschaft nur noch einmal:<\/p>\n<pre>SELECT\r\n     tblMitgliederMN.MitgliedID,\r\n     tblMitgliederMN.PartnerID,\r\n     tblMitgliederMN.Ehepaar\r\nFROM\r\n     tblMitgliederMN\r\nWHERE\r\n     (\r\n         ((tblMitgliederMN.MitgliedID) &lt; [PartnerID])\r\n         AND ((tblMitgliederMN.PartnerID) IS NOT NULL)\r\n     )\r\nORDER BY\r\n     tblMitgliederMN.MitgliedID;<\/pre>\n<p>F&uuml;r diese Abfrage aktivieren wir nun den Abfragetyp <b>Anf&uuml;gen <\/b>und geben als Zieltabelle die Tabelle <b>tblPartnerschaften <\/b>an. Im Entwurf weisen wir das Feld <b>MitgliedID <\/b>dem Feld <b>PartnerA <\/b>und das Feld <b>PartnerID <\/b>dem Feld <b>PartnerB <\/b>hinzu. Das Feld <b>Ehepaar <\/b>weisen wir dem gleichnamigen Feld der Tabelle <b>tblPartnerschaften <\/b>zu (siehe Bild 11).<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2026_01\/pic_1587_010.png\" alt=\"Anf&uuml;geabfrage f&uuml;r die Partnerschaftstabelle\" width=\"424,5589\" height=\"329,1425\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 11: Anf&uuml;geabfrage f&uuml;r die Partnerschaftstabelle<\/span><\/b><\/p>\n<p>F&uuml;hren wir diese Abfrage aus, erhalten wir das Ergebnis aus Bild 12. Durch das Kriterium landen auch nur g&uuml;ltige Datens&auml;tze in dieser Abfrage &#8211; sollte die Tabelle <b>tblMitgliederMN<\/b> zuvor Datens&auml;tze enthalten haben, bei denen <b>PartnerA <\/b>gleich <b>PartnerB <\/b>w&auml;re, oder es g&auml;be inkonsistente Daten, w&uuml;rden diese nicht angelegt werden.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2026_01\/pic_1587_011.png\" alt=\"Ergebnis der Anf&uuml;geabfrage\" width=\"424,5589\" height=\"182,2548\"\/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 12: Ergebnis der Anf&uuml;geabfrage<\/span><\/b><\/p>\n<p>Es ist allerdings nicht auszuschlie&szlig;en, dass f&uuml;r Mitglied <b>1 <\/b>eine Partnerschaft mit Mitglied <b>2 <\/b>angelegt war und f&uuml;r Mitglied <b>2 <\/b>eine Partnerschaft mit Mitglied <b>3<\/b>. Dies k&ouml;nnen wir &uuml;ber das Datenmodell in der aktuellen Form nicht ausschlie&szlig;en und m&uuml;ssten es letztlich &uuml;ber die Anwendungslogik steuern. Allerdings bietet Access auch noch die Datenmakros an. Wie wir damit auch die letzte m&ouml;gliche Fehleingabe verhindern, zeigen wir in den folgenden Abschnitten.<\/p>\n<h2>Doppelte Eingabe in verschiedenen Feldern per Datenmakro verhindern<\/h2>\n<p>Datenmakros sind eine Art Trigger f&uuml;r Access-Tabellen. In diesem Fall nutzen wir das Ereignis <b>Vor Aktualisierung<\/b>, um vor dem Speichern des Datensatzes ein Datenmakro auszul&ouml;sen. Dieses legen wir in der Datenblattansicht mit dem Ribbonbefehl <b>Tabelle|Vorabereignisse|Vor &Auml;nderung <\/b>an (siehe Bild 13).<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2026_01\/pic_1587_012.png\" alt=\"Datenmakro f&uuml;r das Ereignis Vor &Auml;nderung anlegen\" width=\"649,559\" height=\"286,869\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 13: Datenmakro f&uuml;r das Ereignis Vor &Auml;nderung anlegen<\/span><\/b><\/p>\n<p>In diesem Makro, dessen Entwurf wir in Bild 14 sehen, wollen wir untersuchen, ob entweder der Wert f&uuml;r das Feld <b>PartnerA<\/b> oder der Wert f&uuml;r das Feld <b>PartnerB <\/b>bereits in einem der vorhandenen Eintr&auml;ge vorkommt.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2026_01\/pic_1587_013.png\" alt=\"Datenmakro f&uuml;r das Ereignis Vor &Auml;nderung in der Entwurfsansicht\" width=\"700\" height=\"738,4542\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 14: Datenmakro f&uuml;r das Ereignis Vor &Auml;nderung in der Entwurfsansicht<\/span><\/b><\/p>\n<p>In den ersten vier Anweisungen legen wir zun&auml;chst einige lokale Variablen fest:<\/p>\n<ul>\n<li><b>varNeuerPartnerA<\/b>: Wird mit dem Wert des Feldes <b>PartnerA <\/b>f&uuml;r den neu hinzugef&uuml;gten oder bearbeiteten Datensatz der Tabelle <b>tblPartnerschaften <\/b>gef&uuml;llt.<\/li>\n<li><b>varNeuerPartnerB<\/b>: Wird mit dem Wert des Feldes <b>PartnerB <\/b>f&uuml;r den neu hinzugef&uuml;gten oder bearbeiteten Datensatz der Tabelle <b>tblPartnerschaften <\/b>gef&uuml;llt.<\/li>\n<li><b>varPartnerschaftID<\/b>: Wird zun&auml;chst mit dem Wert <b>0 <\/b>gef&uuml;llt und sp&auml;ter genutzt, um die ID eines Datensatzes aufzunehmen, der bereits einen der Werte der Felder <b>PartnerA <\/b>oder <b>PartnerB <\/b>des neu hinzugef&uuml;gten oder bearbeiteten Datensatzes enth&auml;lt.<\/li>\n<li><b>varNeuePartnerschaftID<\/b>: Wird mit der ID des aktuell bearbeiteten oder neu hinzugef&uuml;gten Datensatzes gef&uuml;llt.<\/li>\n<\/ul>\n<p>Danach verwenden wir die Aktion <b>Datensatz nachschlagen <\/b>f&uuml;r die Tabelle <b>tblPartnerschaften<\/b>, wo wir folgende Bedingung angeben:<\/p>\n<pre>[PartnerschaftID]&lt;&gt;[varNeuePartnerschaftID] Und ([PartnerA]=[varNeuerPartnerA] Oder [PartnerB]=[varNeuerPartnerA])<\/pre>\n<p>Wir suchen also nach einem Datensatz, der nicht der aktuell bearbeitete oder neu hinzugef&uuml;gte Datensatz ist (<b>[PartnerschaftID]<>[varNeuePartnerschaftID]<\/b>), und der entweder im Feld <b>PartnerA <\/b>oder <b>PartnerB <\/b>bereits den neuen Wert aus der Variablen <b>varNeuerPartnerA <\/b>enth&auml;lt. Das Ergebnis referenzieren wir mit der Variablen <b>rstPartnerschaften<\/b>.<\/p>\n<p>Danach lesen wir den Wert des Feldes <b>PartnerschaftID <\/b>f&uuml;r den neuen oder bearbeiteten Datensatz in die Variable <b>varPartnerschaftID <\/b>ein.<\/p>\n<p>Ist <b>varPartnerschaftID <\/b>danach ungleich <b>0<\/b>, gibt es mindestens einen Datensatz, in dem der Wert des Feldes <b>PartnerA <\/b>bereits vorkommt. Dies pr&uuml;fen wir in einer <b>Wenn<\/b>-Bedingung. Ist diese erf&uuml;llt, l&ouml;sen wir den Fehler <b>1001 <\/b>aus und geben daf&uuml;r eine Meldung aus, die wie folgt zusammengesetzt wird:<\/p>\n<pre>=\"Mitglied \" & [varNeuerPartnerA] & \" vorhanden\"<\/pre>\n<p>Hat <b>varPartnerschaft <\/b>an dieser Stelle den Wert <b>0<\/b>, pr&uuml;fen wir, ob der Inhalt des neuen oder bearbeiteten Datensatzes f&uuml;r das Feld <b>PartnerB <\/b>bereits in einem vorhandenen Datensatz au&szlig;er dem aktuellen Datensatz vorkommt. Der Ablauf ist der gleiche wie bei der Pr&uuml;fung auf das Feld <b>PartnerA<\/b>. Hier geben wir bei der Fehlermeldung allerdings den Wert des bereits vorhandenen Eintrags f&uuml;r das Feld <b>PartnerB <\/b>aus.<\/p>\n<p>Auf diese Weise fangen wir &uuml;ber das Datenmodell alle m&ouml;glichen Fehleingaben ab. Wenn Sie das Datenmakro auf die eigene Datenbank &uuml;bertragen wollen, markieren Sie einfach den kompletten Makro-Inhalt und f&uuml;gen diesen in das Makro f&uuml;r die Zieltabelle ein. Wenn man den Inhalt der Zwischenablage in einen Texteditor einf&uuml;gt, sieht man, dass es sich hierbei um ein XML-Dokument handelt. Nun schauen wir uns an, wie wir die Benutzeroberfl&auml;che auf das neue Datenmodell anpassen.<\/p>\n<h2>Formular an das neue Datenmodell anpassen<\/h2>\n<p>Bisher hatten wir im Formular <b>frmMitglieder<\/b> einfach ein Kombinationsfeld zur Auswahl des Partners. Das k&ouml;nnen wir auch beibehalten, aber es wird ein wenig komplizierter, das Formular an das neue Datenmodell anzupassen.<\/p>\n<p>Der erste Schritt ist, dass wir das Formular <b>frmMitglieder <\/b>in ein neues Formular namens <b>frmMitgliederMN <\/b>kopieren und mit diesem weiterarbeiten.<\/p>\n<p>Dann weisen wir diesem die Kopie der Tabelle namens <b>tblMitgliederMN <\/b>als Datensatzquelle zu (siehe Bild 15). In dieser l&ouml;schen wir zuvor die beiden Felder <b>PartnerID <\/b>und <b>Ehepaar<\/b>, denn diese Informationen werden nun in der Tabelle <b>tblPartnerschaften <\/b>gespeichert.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2026_01\/pic_1587_014.png\" alt=\"Entwurf des Formulars frmMitgliederMN\" width=\"549,559\" height=\"332,2914\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 15: Entwurf des Formulars frmMitgliederMN<\/span><\/b><\/p>\n<p>Au&szlig;erdem entfernen wir f&uuml;r die beiden Steuerelemente <b>cboPartnerID <\/b>und <b>chkEhepaar <\/b>die Werte f&uuml;r die Eigenschaft <b>Steuerelementinhalt<\/b>. Wir k&ouml;nnen diese nicht mehr direkt zuweisen, da diese nicht mehr in der Datensatzquelle des Formulars enthalten sind.<\/p>\n<h2>F&uuml;llen der Steuerelemente cboPartnerID und chkEhepaar<\/h2>\n<p>Die beiden Steuerelemente <b>cboPartnerID <\/b>und <b>chkEhepaar <\/b>sollen immer beim Anzeigen eines Datensatzes gef&uuml;llt werden. Dazu hinterlegen wir eine Ereignisprozedur f&uuml;r die Eigenschaft <b>Beim Anzeigen <\/b>des Formulars, in der wir nur den Aufruf einer weiteren Prozedur hinterlegen:<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>Form_Current()\r\n     <span style=\"color:blue;\">Call<\/span> UpdateControls\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Die Prozedur <b>UpdateControls <\/b>finden wir in Listing 1. Sie hat die Aufgabe, die beiden nicht gebundenen Steuerelemente mit den jeweiligen Werten aus der Tabelle <b>tblPartnerschaften <\/b>zu f&uuml;llen.<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>UpdateControls()\r\n     <span style=\"color:blue;\">Dim <\/span>db<span style=\"color:blue;\"> As <\/span>DAO.Database\r\n     <span style=\"color:blue;\">Dim <\/span>rst<span style=\"color:blue;\"> As <\/span>DAO.Recordset\r\n     <span style=\"color:blue;\">Dim <\/span>strSQL<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>varPartnerID<span style=\"color:blue;\"> As Variant<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>bolEhepaar<span style=\"color:blue;\"> As Boolean<\/span>\r\n     \r\n     <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Not<\/span> Me.NewRecord Or Me.Dirty<span style=\"color:blue;\"> Then<\/span>\r\n         Me.cboPartnerID.Enabled = <span style=\"color:blue;\">True<\/span>\r\n         Me.chkEhepaar.Enabled = <span style=\"color:blue;\">True<\/span>\r\n     <span style=\"color:blue;\">Else<\/span>\r\n         Me.cboPartnerID.Enabled = <span style=\"color:blue;\">False<\/span>\r\n         Me.chkEhepaar.Enabled = <span style=\"color:blue;\">False<\/span>\r\n     <span style=\"color:blue;\">End If<\/span>\r\n     \r\n     <span style=\"color:blue;\">Set<\/span> db = CurrentDb\r\n     <span style=\"color:blue;\">Set<\/span> rst = db.OpenRecordset(\"SELECT * FROM tblPartnerschaften\", dbOpenDynaset)\r\n     rst.FindFirst \"PartnerB = \" & Nz(Me.MitgliedID, 0)\r\n     <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Not<\/span> rst.NoMatch<span style=\"color:blue;\"> Then<\/span>\r\n         varPartnerID = rst!PartnerA\r\n         bolEhepaar = rst!Ehepaar\r\n     <span style=\"color:blue;\">Else<\/span>\r\n         rst.FindFirst \"PartnerA = \" & Nz(Me.MitgliedID, 0)\r\n         <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Not<\/span> rst.NoMatch<span style=\"color:blue;\"> Then<\/span>\r\n             varPartnerID = rst!PartnerB\r\n             bolEhepaar = rst!Ehepaar\r\n         <span style=\"color:blue;\">Else<\/span>\r\n             varPartnerID = Null\r\n             bolEhepaar = <span style=\"color:blue;\">False<\/span>\r\n         <span style=\"color:blue;\">End If<\/span>\r\n     <span style=\"color:blue;\">End If<\/span>\r\n     Me.cboPartnerID = varPartnerID\r\n     Me.chkEhepaar = bolEhepaar\r\n     <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Not<\/span> (Nz(Me.cboPartnerID, 0) = 0)<span style=\"color:blue;\"> Then<\/span>\r\n         Me.chkEhepaar.Enabled = <span style=\"color:blue;\">True<\/span>\r\n     <span style=\"color:blue;\">Else<\/span>\r\n         Me.chkEhepaar.Enabled = <span style=\"color:blue;\">False<\/span>\r\n     <span style=\"color:blue;\">End If<\/span>\r\n     strSQL = \"SELECT MitgliedID, Vorname & '' '' & Nachname AS Mitglied FROM tblMitgliederMN WHERE (((MitgliedID) &lt;&gt; \" _\r\n         & Nz(Me.MitgliedID, 0) & \" AND (MitgliedID) NOT IN (SELECT PartnerA FROM tblPartnerschaften) \" _\r\n         & \"AND (MitgliedID) NOT IN (SELECT PartnerB FROM tblPartnerschaften))) OR MitgliedID = \" _\r\n         & Nz(varPartnerID, 0) & \";\"\r\n     Me.cboPartnerID.RowSource = strSQL\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 1: Prozedur zum Aktualisieren der Steuerelemente cboPartnerID und chkEhepaar<\/span><\/b><\/p>\n<p>Sie deklariert zun&auml;chst einige Variablen, unter anderem f&uuml;r das aktuelle <b>Database<\/b>-Objekt und f&uuml;r ein Recordset auf Basis der Tabelle <b>tblPartnerschaften<\/b>. Au&szlig;erdem ben&ouml;tigen wir eine Variable zum Zusammenstellen einer SQL-Abfrage (<b>strSQL<\/b>), zum Referenzieren des jeweiligen Partners des aktuellen Mitglieds (<b>varPartnerID<\/b>) und f&uuml;r die Angabe, ob es sich bei der Partnerschaft um ein Ehepaar handelt (<b>bolEhepaar<\/b>).<\/p>\n<p>Im ersten Schritt pr&uuml;ft die Prozedur, ob das Formular aktuell einen nicht neuen (<b>Not Me.NewRecord<\/b>) oder einen in Bearbeitung befindlichen Datensatz anzeigt (<b>Me.Dirty<\/b>). Ist eine der beiden Bedingungen wahr, werden die beiden Steuerelemente <b>cboPartnerID <\/b>und <b>chkEhepaar <\/b>aktiviert. Anderenfalls werden sie deaktiviert.<\/p>\n<p>Dies sorgt daf&uuml;r, dass die beiden Steuerelemente bei einem neuen, leeren Datensatz, der noch nicht bearbeitet wurde, noch nicht zur Auswahl eines Partners genutzt werden k&ouml;nnen. Das ist notwendig, da es zu diesem Zeitpunkt noch keinen Wert im Feld <b>MitgliedID <\/b>gibt, den wir in die Tabelle <b>tblPartnerschaften <\/b>eintragen k&ouml;nnten.<\/p>\n<p>Danach f&uuml;llen wir ein Recordset mit den Datens&auml;tzen der Tabelle <b>tblPartnerschaften<\/b>. Die folgenden Schritte dienen dazu, herauszufinden, ob das aktuell angezeigte Mitglied bereits einen Partner hat. Dazu durchsuchen wir das Recordset zun&auml;chst mit <b>rst.FindFirst <\/b>nach einem Datensatz, der die <b>MitgliedID <\/b>des aktuell angezeigten Mitglieds im Feld <b>PartnerB <\/b>enth&auml;lt.<\/p>\n<p>Ist das der Fall, liefert die Eigenschaft <b>NoMatch <\/b>den Wert <b>False <\/b>und die erste Bedingung ist erf&uuml;llt. Wenn in <b>PartnerB <\/b>das aktuelle Mitglied ist, k&ouml;nnen wir aus dem Feld <b>PartnerA <\/b>den Partner des aktuellen Mitglieds entnehmen und diesen in die Variable <b>varPartnerID <\/b>eintragen. Au&szlig;erdem lesen wir aus dem Feld <b>Ehepaar <\/b>den Wert f&uuml;r die Variable <b>bolEhepaar <\/b>aus.<\/p>\n<p>Sollten wir keinen Datensatz finden, in dem f&uuml;r das Feld <b>PartnerB <\/b>die ID des aktuell angezeigten Mitglieds eingetragen ist, durchsuchen wir in n&auml;chsten Schritt das Feld <b>PartnerA <\/b>nach diesem Wert.<\/p>\n<p>Finden wir einen passenden Eintrag, legen wir <b>varPartnerID <\/b>auf den Wert des Feldes <b>PartnerB <\/b>fest und <b>bolEhepaar <\/b>wieder auf den Wert aus dem Feld <b>Ehepaar<\/b>.<\/p>\n<p>Liefert auch diese Suche kein Ergebnis, stellen wir <b>varPartner <\/b>auf <b>Null <\/b>und <b>bolEhepaar <\/b>auf <b>False <\/b>ein. Letzteres ist nicht unbedingt n&ouml;tig, da ein <b>Boolean<\/b>-Feld ohnehin mit dem Wert <b>False <\/b>initialisiert wird, aber die <b>Variant<\/b>-Variable <b>varPartnerID <\/b>hat standardm&auml;&szlig;ig den Wert <b>Empty <\/b>und muss mit <b>Null <\/b>gef&uuml;llt werden, damit die folgenden Schritte funktionieren.<\/p>\n<p>Schlie&szlig;lich stellen wir das Steuerelement <b>cboPartnerID <\/b>auf den Wert aus <b>varPartnerID <\/b>ein und das Steuerelement <b>chkEhepaar <\/b>auf den Wert aus <b>bolEhepaar<\/b>.<\/p>\n<p>Danach pr&uuml;fen wir, ob <b>cboPartner <\/b>nun einen Wert enth&auml;lt, und aktivieren in diesem Fall das Kontrollk&auml;stchen <b>chkEhepaar<\/b>.<\/p>\n<h2>Kombinationsfeld cboPartnerID f&uuml;llen<\/h2>\n<p>Schlie&szlig;lich stellen wir die Datensatzherkunft f&uuml;r das Kombinationsfeld <b>cboPartnerID <\/b>zusammen, das alle verf&uuml;gbaren Mitglieder anzeigen soll.<\/p>\n<p>Die ben&ouml;tigte SQL-Anweisung soll alle Datens&auml;tze der Tabelle <b>tblMitglieder <\/b>liefern, die folgende Bedingungen erf&uuml;llen:<\/p>\n<ul>\n<li>Das aktuell angezeigte Mitglied soll ausgeschlossen werden. Eine Partnerschaft mit sich selbst ist schlie&szlig;lich nicht m&ouml;glich.<\/li>\n<li>Alle weiteren Mitglieder, die &uuml;ber die Tabelle <b>tblPartnerschaften <\/b>noch keiner anderen Partnerschaft zugeordnet sind.<\/li>\n<li>Das Mitglied entspricht dem aktuell festgelegten Partner (dies ist n&ouml;tig, damit der gew&auml;hlte Eintrag &uuml;berhaupt im Kombinationsfeld angezeigt wird).<\/li>\n<\/ul>\n<p>Wenn wir die Abfrage beispielsweise f&uuml;r das Mitglied mit der ID <b>1 <\/b>und mit der Partnerin mit der ID <b>2 <\/b>zusammenstellen, sieht diese wie in Bild 16 aus.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2026_01\/pic_1587_015.png\" alt=\"Abfrage zum Ermitteln der m&ouml;glichen Partner\" width=\"424,5589\" height=\"416,8552\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 16: Abfrage zum Ermitteln der m&ouml;glichen Partner<\/span><\/b><\/p>\n<p>Der erste Teil der <b>WHERE<\/b>-Klausel schlie&szlig;t das aktuelle Mitglied aus der Ergebnisliste aus. Der zweite Teil holt alle Mitglieder, deren <b>MitgliedID <\/b>weder im Feld <b>PartnerA <\/b>noch im Feld <b>PartnerB <\/b>der Tabelle <b>tblPartnerschaften <\/b>enthalten ist. Der letzte Teil stellt sicher, dass auch der aktuelle Partner des Mitglieds in der Auswahl erscheint.<\/p>\n<h2>Speichern eines neu ausgew&auml;hlten Partners<\/h2>\n<p>Da das Steuerelement <b>cboPartnerID <\/b>ungebunden ist, m&uuml;ssen wir einen neu ausgew&auml;hlten Eintrag per VBA-Code in der Tabelle <b>tblPartnerschaften <\/b>speichern.<\/p>\n<p>Dazu wird das Ereignis <b>Nach Aktualisierung <\/b>dieses Steuerelements verwendet, f&uuml;r das wir die folgende Prozedur hinterlegen:<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>cboPartnerID_AfterUpdate()\r\n     <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Not<\/span> (Nz(Me.cboPartnerID, 0) = 0)<span style=\"color:blue;\"> Then<\/span>\r\n         Me.chkEhepaar.Enabled = <span style=\"color:blue;\">True<\/span>\r\n     <span style=\"color:blue;\">Else<\/span>\r\n         Me.chkEhepaar.Enabled = <span style=\"color:blue;\">False<\/span>\r\n     <span style=\"color:blue;\">End If<\/span>\r\n     <span style=\"color:blue;\">Call<\/span> SavePartner\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Die Prozedur pr&uuml;ft, ob das Kombinationsfeld <b>cboPartnerID <\/b>nach der Aktualisierung einen Wert enth&auml;lt. In diesem Fall wird das Steuerelement <b>chkEhepaar <\/b>aktiviert. Wenn das Kombinationsfeld <b>cboPartnerID <\/b>geleert wurde, wird <b>chkEhepaar <\/b>deaktiviert.<\/p>\n<p>Au&szlig;erdem wird die Prozedur <b>SavePartner <\/b>aufgerufen, welche das eigentliche Speichern des ausgew&auml;hlten Partners &uuml;bernimmt. Diese Prozedur finden Sie in Listing 2.<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>SavePartner()\r\n     <span style=\"color:blue;\">Dim <\/span>db<span style=\"color:blue;\"> As <\/span>DAO.Database\r\n     <span style=\"color:blue;\">Dim <\/span>lngPartnerA<span style=\"color:blue;\"> As Long<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>lngPartnerB<span style=\"color:blue;\"> As Long<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>strEhepaar<span style=\"color:blue;\"> As String<\/span>\r\n     \r\n     <span style=\"color:blue;\">Set<\/span> db = CurrentDb\r\n     Me.Dirty = <span style=\"color:blue;\">False<\/span>\r\n     \r\n     <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Not<\/span> <span style=\"color:blue;\">Len<\/span>(Nz(Me.cboPartnerID, \"\")) = 0<span style=\"color:blue;\"> Then<\/span>\r\n         <span style=\"color:blue;\">If <\/span>Me.MitgliedID &gt; CLng(Me.cboPartnerID)<span style=\"color:blue;\"> Then<\/span>\r\n             lngPartnerA = Me.cboPartnerID\r\n             lngPartnerB = Me.MitgliedID\r\n         <span style=\"color:blue;\">Else<\/span>\r\n             lngPartnerA = Me.MitgliedID\r\n             lngPartnerB = Me.cboPartnerID\r\n         <span style=\"color:blue;\">End If<\/span>\r\n         <span style=\"color:blue;\">If <\/span>Me.chkEhepaar = <span style=\"color:blue;\">True<\/span><span style=\"color:blue;\"> Then<\/span>\r\n             strEhepaar = \"True\"\r\n         <span style=\"color:blue;\">Else<\/span>\r\n             strEhepaar = \"False\"\r\n         <span style=\"color:blue;\">End If<\/span>\r\n         db.Execute \"DELETE FROM tblPartnerschaften WHERE PartnerA IN (\" & lngPartnerA & \", \" _\r\n             & lngPartnerB & \") OR PartnerB IN (\" & lngPartnerA & \", \" & lngPartnerB & \")\", dbFailOnError\r\n         db.Execute \"INSERT INTO tblPartnerschaften(PartnerA, PartnerB, Ehepaar) VALUES(\" _\r\n             & lngPartnerA & \", \" & lngPartnerB & \", \" & strEhepaar & \")\", dbFailOnError\r\n     <span style=\"color:blue;\">Else<\/span>\r\n         db.Execute \"DELETE FROM tblPartnerschaften WHERE \" & Me.MitgliedID & \" IN (PartnerA, PartnerB)\", dbFailOnError\r\n     <span style=\"color:blue;\">End If<\/span>\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 2: Prozedur zum Speichern des neu gew&auml;hlten Partners<\/span><\/b><\/p>\n<p>Die Prozedur deklariert ein <b>Database<\/b>-Objekt sowie zwei Variablen f&uuml;r den ersten und den zweiten Partner der Partnerschaft (<b>lngPartnerA <\/b>und <b>lngPartnerB<\/b>). Au&szlig;erdem ben&ouml;tigen wir eine <b>String<\/b>-Variable f&uuml;r das Feld <b>Ehepaar<\/b>.<\/p>\n<p>Die Prozedur speichert zun&auml;chst mit <b>Me.Dirty = False <\/b>den aktuellen Datensatz im Formular.<\/p>\n<p>Dann pr&uuml;ft sie, ob der Wert des Kombinationsfeldes <b>cboPartnerID <\/b>nicht <b>Null <\/b>ist. Ist das nicht der Fall, untersucht sie, ob der Wert des Feldes <b>MitgliedID <\/b>des aktuellen Mitglieds aus dem Formular gr&ouml;&szlig;er ist als die ID des gew&auml;hlten Partners aus dem Kombinationsfeld <b>cboPartnerID<\/b>.<\/p>\n<p>Diese Unterscheidung ist n&ouml;tig, damit wir festlegen k&ouml;nnen, welcher Partner als <b>PartnerA <\/b>und welcher als <b>PartnerB <\/b>eingetragen wird. Zur Erinnerung: Wir hatten als G&uuml;ltigkeitsregel in der Tabellendefinition festgelegt, dass die ID von <b>PartnerA <\/b>immer kleiner als die von <b>PartnerB <\/b>sein muss.<\/p>\n<p>Ist <b>MitgliedID <\/b>gr&ouml;&szlig;er als die <b>PartnerID <\/b>ist, wird die <b>MitgliedID <\/b>in der Variablen <b>lngPartnerB <\/b>und die ID des Partners in <b>lngPartnerA <\/b>gespeichert und umgekehrt.<\/p>\n<p>Wenn das Kontrollk&auml;stchen <b>chkEhepaar <\/b>aktiviert ist, erh&auml;lt die Variable <b>strEhepaar <\/b>die Zeichenkette <b>True<\/b>, sonst <b>False<\/b>. Warum speichern wir diesen Wert als String?<\/p>\n<p>Weil wir diesen gleich in einer <b>INSERT INTO<\/b>-Anweisung nutzen wollen und wir dort nicht direkt einen <b>Boolean<\/b>-Wert angeben k&ouml;nnen, da dieser in der deutschen Access-Version als <b>Wahr <\/b>oder <b>Falsch <\/b>interpretiert wird, was einen Fehler ausl&ouml;sen w&uuml;rde.<\/p>\n<p>Danach entfernen wir zun&auml;chst die Eintr&auml;ge aus der Tabelle <b>tblPartnerschaften<\/b>, die im Feld <b>PartnerA <\/b>oder <b>PartnerB <\/b>einen der beiden Werte aus <b>lngPartnerA <\/b>oder <b>lngPartnerB <\/b>enthalten.<\/p>\n<p>Dies ist n&ouml;tig, wenn wir den Partner eines Mitglieds austauschen, statt diesen f&uuml;r einen bisher nicht vorhandenen Partner hinzuzuf&uuml;gen.<\/p>\n<p>Danach k&ouml;nnen wir schlie&szlig;lich die neue Partnerschaft in die Tabelle <b>tblPartnerschaften <\/b>eintragen, was wir mit einer <b>INSERT INTO<\/b>-Anweisung erledigen.<\/p>\n<p>Wenn wir beispielsweise f&uuml;r das Mitglied <b>1 <\/b>das Mitglied <b>2 <\/b>eintragen, und die Partnerschaft als Ehepaar definiert werden soll, sieht die Abfrage wie folgt aus:<\/p>\n<pre>INSERT INTO tblPartnerschaften(PartnerA, PartnerB, Ehepaar) VALUES(1, 2, <span style=\"color:blue;\">False<\/span>)<\/pre>\n<p>Schlie&szlig;lich fehlt noch der <b>Else<\/b>-Teil der Bedingung, die gepr&uuml;ft hat, ob &uuml;berhaupt ein neuer Partner ausgew&auml;hlt oder gegebenenfalls der vorhandene Partner entfernt wurde.<\/p>\n<p>Wurde der Partner entfernt, rufen wir eine <b>DELETE<\/b>-Anweisung auf, welche die Partnerschaft entfernt, an der das aktuell angezeigte Mitglied als <b>PartnerA <\/b>oder <b>PartnerB <\/b>beteiligt ist. Wenn wir die Partnerschaft f&uuml;r das Mitglied mit der ID <b>1 <\/b>entfernen, sieht die Abfrage wie folgt aus:<\/p>\n<pre>DELETE FROM tblPartnerschaften \r\nWHERE 1 IN (PartnerA, PartnerB)<\/pre>\n<h2>Ehepaar-Eigenschaft setzen oder entfernen<\/h2>\n<p>Wenn wir f&uuml;r eine bestehende Partnerschaft im Formular die Eigenschaft <b>Ehepaar <\/b>setzen oder entfernen, l&ouml;st dies das Ereignis <b>Nach Aktualisierung <\/b>des Steuerelements <b>chkEhepaar <\/b>aus. F&uuml;r diese haben wir die folgende Prozedur hinterlegt:<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>chkEhepaar_AfterUpdate()\r\n     <span style=\"color:blue;\">Call<\/span> SavePartner\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Sie ruft wiederum die Prozedur <b>SavePartner <\/b>auf, die dann zwar lediglich den Wert des Feldes Ehepaar &auml;ndern m&uuml;sste, aber da wir dazu ohnehin wieder <b>PartnerA <\/b>und <b>PartnerB <\/b>ermitteln m&uuml;ssten, verwenden wir hier einfach die Prozedur <b>SavePartner <\/b>erneut.<\/p>\n<h2>Vorgehensweise bei neuen Datens&auml;tzen<\/h2>\n<p>Wenn der Benutzer einen neuen Datensatz zum Formular <b>frmMitgliederMN <\/b>hinzuf&uuml;gt, m&uuml;ssen wir eine kleine Sonderbehandlung einbauen. Der Grund ist, dass wir, sobald das erste Zeichen in eines der Felder <b>Vorname <\/b>oder <b>Nachname <\/b>eingegeben wurde, das Kombinationsfeld <b>cboPartnerID <\/b>und das Kontrollk&auml;stchen <b>chkEhepaar <\/b>aktivieren wollen. Wir k&ouml;nnten auch einzelne Ereignisprozeduren nutzen, die durch das Ereignis <b>Bei &Auml;nderung <\/b>eines dieser Steuerelemente ausgel&ouml;st werden, aber da in der Regel noch viele weitere Felder zu einem Mitglied geh&ouml;ren, wollen wir einen anderen Weg w&auml;hlen.<\/p>\n<p>Also nutzen wir zun&auml;chst das Ereignis <b>Bei &Auml;nderung <\/b>des Formulars selbst. Hier aktivieren wir zun&auml;chst die beiden Steuerelemente <b>cboPartnerID <\/b>und <b>chkEhepaar<\/b>.<\/p>\n<p>Dann w&uuml;rden wir eigentlich gern direkt die Datensatzherkunft des Kombinationsfeldes <b>cboPartnerID <\/b>mit den verf&uuml;gbaren Partnern f&uuml;llen. Das gelingt allerdings nicht, weil der neue Wert f&uuml;r das Feld <b>MitgliedID <\/b>direkt nach dem Versetzen des Datensatzes in den <b>Dirty<\/b>-Zustand noch nicht verf&uuml;gbar ist. Dies dauert ein paar Millisekunden, weshalb wir den Formular-Timer auf 100 Millisekunden einstellen:<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>Form_Dirty(Cancel<span style=\"color:blue;\"> As Integer<\/span>)\r\n     Me.cboPartnerID.Enabled = <span style=\"color:blue;\">True<\/span>\r\n     Me.chkEhepaar.Enabled = <span style=\"color:blue;\">True<\/span>\r\n     Me.TimerInterval = 100\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Erst dann wird das Ereignis <b>Form_Timer <\/b>ausgel&ouml;st, das wir wie folgt definieren:<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>Form_Timer()\r\n     Me.TimerInterval = 0\r\n     <span style=\"color:blue;\">Call<\/span> UpdateControls\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Hier deaktivieren wir zuerst den Timer (das sollte beim Timer immer der erste Schritt sein) und rufen dann die Prozedur <b>UpdateControls <\/b>auf, die wir bereits weiter oben beschrieben haben und die das Kombinationsfeld mit den verf&uuml;gbaren Partnern f&uuml;llt.<\/p>\n<h2>Verwerfen eines neuen Datensatzes<\/h2>\n<p>Sollte der Benutzer einen neuen Datensatz zun&auml;chst in den <b>Dirty<\/b>-Zustand versetzen, und diesen dann zum Beispiel mit der <b>Escape<\/b>-Taste verwerfen, sollen die beiden Steuerelemente <b>cboPartnerID <\/b>und <b>chkEhepaar <\/b>wieder deaktiviert werden.<\/p>\n<p>Das erledigen wir mit der Prozedur f&uuml;r die Ereigniseigenschaft <b>Bei R&uuml;ckg&auml;ngig <\/b>des Formulars. Diese pr&uuml;ft, ob das Formular aktuell einen neuen Datensatz anzeigt, und deaktiviert in diesem Fall die beiden Steuerelemente wieder:<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>Form_Undo(Cancel<span style=\"color:blue;\"> As Integer<\/span>)\r\n     <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Not<\/span> Me.NewRecord<span style=\"color:blue;\"> Then<\/span>\r\n         Me.cboPartnerID.Enabled = <span style=\"color:blue;\">True<\/span>\r\n         Me.chkEhepaar.Enabled = <span style=\"color:blue;\">True<\/span>\r\n     <span style=\"color:blue;\">Else<\/span>\r\n         Me.cboPartnerID.Enabled = <span style=\"color:blue;\">False<\/span>\r\n         Me.chkEhepaar.Enabled = <span style=\"color:blue;\">False<\/span>\r\n     <span style=\"color:blue;\">End If<\/span>\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<h2>Zusammenfassung und Ausblick<\/h2>\n<p>Dieser Beitrag zeigt, wie sich eine reflexive 1:n-Beziehung zur Verwaltung von Partnerschaften in eine m:n-Beziehung &uuml;berf&uuml;hren l&auml;sst und wie die Daten anschlie&szlig;end in einem angepassten Formular verwaltet werden k&ouml;nnen.<\/p>\n<p>Dabei wurde beachtet, dass jegliche ung&uuml;ltige Kombinationen durch Restriktionen im Datenmodell verhindert werden k&ouml;nnen.<\/p>\n<h2>Downloads zu diesem Beitrag<\/h2>\n<p>Enthaltene Beispieldateien:<\/p>\n<p>1nBeziehungenInmnBeziehungentransformieren.accdb<\/p>\n<p><a href=\"..\/fileadmin\/beispiele\/DBB87F3F-FC96-42E8-9DF8-AD641859DFFF\/aiu_1587.zip\">Download<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Manchmal legt man eine 1:n-Beziehung zwischen zwei Tabellen an, um sp&auml;ter festzustellen, dass eine m:n-Beziehung doch die funktionalere Variante ist. Ein Beispiel sind reflexive Beziehungen, mit denen man etwa Vater-Kind-Beziehungen abbildet oder Partner-Beziehungen. Andere Beispiele sind solche wie zwischen Produkten und Kategorien &#8211; man dachte zun&auml;chst, dass es reicht, wenn man jedes Produkt nur einer Kategorie zuordnen kann, aber man dann erkennt, dass es f&uuml;r verschiedene Anwendungsf&auml;lle doch g&uuml;nstiger w&auml;re, wenn man ein Produkt mehr als einer Kategorie zuordnen kann. &Auml;hnliche F&auml;lle sind Mitarbeiter und Funktionen oder Abteilungen. In diesem Beitrag schauen wir uns das Beispiel eines Kunden an, der in seinem Sportverein partnerschaftliche Beziehungen &uuml;ber ein Fremdschl&uuml;sselfeld der Tabelle tblMitglieder auf diese selbst abgebildet hat. Hier gab es mehrere Gr&uuml;nde, um diese Beziehung in eine m:n-Beziehung umzuwandeln. Welche das sind und wie wir die Umwandlung durchgef&uuml;hrt haben, lesen Sie in diesem Beitrag.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"om_disable_all_campaigns":false,"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"_uf_show_specific_survey":0,"_uf_disable_surveys":false,"footnotes":""},"categories":[66012026,662026,44000021],"tags":[],"class_list":["post-55001587","post","type-post","status-publish","format-standard","hentry","category-66012026","category-662026","category-Tabellen_und_Datenmodellierung"],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v20.9 (Yoast SEO v27.3) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>Reflexive 1:n-Beziehung zu m:n-Beziehung - Access im Unternehmen<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/access-im-unternehmen.de\/Reflexive_1nBeziehung_zu_mnBeziehung\/\" \/>\n<meta property=\"og:locale\" content=\"de_DE\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Reflexive 1:n-Beziehung zu m:n-Beziehung\" \/>\n<meta property=\"og:description\" content=\"Manchmal legt man eine 1:n-Beziehung zwischen zwei Tabellen an, um sp&auml;ter festzustellen, dass eine m:n-Beziehung doch die funktionalere Variante ist. Ein Beispiel sind reflexive Beziehungen, mit denen man etwa Vater-Kind-Beziehungen abbildet oder Partner-Beziehungen. Andere Beispiele sind solche wie zwischen Produkten und Kategorien - man dachte zun&auml;chst, dass es reicht, wenn man jedes Produkt nur einer Kategorie zuordnen kann, aber man dann erkennt, dass es f&uuml;r verschiedene Anwendungsf&auml;lle doch g&uuml;nstiger w&auml;re, wenn man ein Produkt mehr als einer Kategorie zuordnen kann. &Auml;hnliche F&auml;lle sind Mitarbeiter und Funktionen oder Abteilungen. In diesem Beitrag schauen wir uns das Beispiel eines Kunden an, der in seinem Sportverein partnerschaftliche Beziehungen &uuml;ber ein Fremdschl&uuml;sselfeld der Tabelle tblMitglieder auf diese selbst abgebildet hat. Hier gab es mehrere Gr&uuml;nde, um diese Beziehung in eine m:n-Beziehung umzuwandeln. Welche das sind und wie wir die Umwandlung durchgef&uuml;hrt haben, lesen Sie in diesem Beitrag.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/access-im-unternehmen.de\/Reflexive_1nBeziehung_zu_mnBeziehung\/\" \/>\n<meta property=\"og:site_name\" content=\"Access im Unternehmen\" \/>\n<meta property=\"article:published_time\" content=\"2026-02-06T13:37:56+00:00\" \/>\n<meta property=\"og:image\" content=\"http:\/\/vg01.met.vgwort.de\/na\/7bf4cb1679ba4ea685ab6870b1c08061\" \/>\n<meta name=\"author\" content=\"Andr\u00e9 Minhorst\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Verfasst von\" \/>\n\t<meta name=\"twitter:data1\" content=\"Andr\u00e9 Minhorst\" \/>\n\t<meta name=\"twitter:label2\" content=\"Gesch\u00e4tzte Lesezeit\" \/>\n\t<meta name=\"twitter:data2\" content=\"26\u00a0Minuten\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Reflexive_1nBeziehung_zu_mnBeziehung\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Reflexive_1nBeziehung_zu_mnBeziehung\\\/\"},\"author\":{\"name\":\"Andr\u00e9 Minhorst\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#\\\/schema\\\/person\\\/13395c4bcd7d7963efe33be9c584d93f\"},\"headline\":\"Reflexive 1:n-Beziehung zu m:n-Beziehung\",\"datePublished\":\"2026-02-06T13:37:56+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Reflexive_1nBeziehung_zu_mnBeziehung\\\/\"},\"wordCount\":4533,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#organization\"},\"image\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Reflexive_1nBeziehung_zu_mnBeziehung\\\/#primaryimage\"},\"thumbnailUrl\":\"http:\\\/\\\/vg01.met.vgwort.de\\\/na\\\/7bf4cb1679ba4ea685ab6870b1c08061\",\"articleSection\":[\"1\\\/2026\",\"2026\",\"Tabellen und Datenmodellierung\"],\"inLanguage\":\"de\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/access-im-unternehmen.de\\\/Reflexive_1nBeziehung_zu_mnBeziehung\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Reflexive_1nBeziehung_zu_mnBeziehung\\\/\",\"url\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Reflexive_1nBeziehung_zu_mnBeziehung\\\/\",\"name\":\"Reflexive 1:n-Beziehung zu m:n-Beziehung - Access im Unternehmen\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Reflexive_1nBeziehung_zu_mnBeziehung\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Reflexive_1nBeziehung_zu_mnBeziehung\\\/#primaryimage\"},\"thumbnailUrl\":\"http:\\\/\\\/vg01.met.vgwort.de\\\/na\\\/7bf4cb1679ba4ea685ab6870b1c08061\",\"datePublished\":\"2026-02-06T13:37:56+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Reflexive_1nBeziehung_zu_mnBeziehung\\\/#breadcrumb\"},\"inLanguage\":\"de\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/access-im-unternehmen.de\\\/Reflexive_1nBeziehung_zu_mnBeziehung\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Reflexive_1nBeziehung_zu_mnBeziehung\\\/#primaryimage\",\"url\":\"http:\\\/\\\/vg01.met.vgwort.de\\\/na\\\/7bf4cb1679ba4ea685ab6870b1c08061\",\"contentUrl\":\"http:\\\/\\\/vg01.met.vgwort.de\\\/na\\\/7bf4cb1679ba4ea685ab6870b1c08061\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Reflexive_1nBeziehung_zu_mnBeziehung\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/access-im-unternehmen.de\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Reflexive 1:n-Beziehung zu m:n-Beziehung\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#website\",\"url\":\"https:\\\/\\\/access-im-unternehmen.de\\\/\",\"name\":\"Access im Unternehmen\",\"description\":\"Das Magazin f\u00fcr Datenbankentwickler auf Basis von Microsoft Access\",\"publisher\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/access-im-unternehmen.de\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"de\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#organization\",\"name\":\"Andr\u00e9 Minhorst Verlag\",\"url\":\"https:\\\/\\\/access-im-unternehmen.de\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/access-im-unternehmen.de\\\/wp-content\\\/uploads\\\/2019\\\/09\\\/aiu_wp.png\",\"contentUrl\":\"https:\\\/\\\/access-im-unternehmen.de\\\/wp-content\\\/uploads\\\/2019\\\/09\\\/aiu_wp.png\",\"width\":370,\"height\":111,\"caption\":\"Andr\u00e9 Minhorst Verlag\"},\"image\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#\\\/schema\\\/logo\\\/image\\\/\"}},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#\\\/schema\\\/person\\\/13395c4bcd7d7963efe33be9c584d93f\",\"name\":\"Andr\u00e9 Minhorst\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/1b9d010cf1716692cb9c34f21554e07d17d461acaea5b61b8cb21cbec678d48a?s=96&d=mm&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/1b9d010cf1716692cb9c34f21554e07d17d461acaea5b61b8cb21cbec678d48a?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/1b9d010cf1716692cb9c34f21554e07d17d461acaea5b61b8cb21cbec678d48a?s=96&d=mm&r=g\",\"caption\":\"Andr\u00e9 Minhorst\"}}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Reflexive 1:n-Beziehung zu m:n-Beziehung - Access im Unternehmen","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/access-im-unternehmen.de\/Reflexive_1nBeziehung_zu_mnBeziehung\/","og_locale":"de_DE","og_type":"article","og_title":"Reflexive 1:n-Beziehung zu m:n-Beziehung","og_description":"Manchmal legt man eine 1:n-Beziehung zwischen zwei Tabellen an, um sp&auml;ter festzustellen, dass eine m:n-Beziehung doch die funktionalere Variante ist. Ein Beispiel sind reflexive Beziehungen, mit denen man etwa Vater-Kind-Beziehungen abbildet oder Partner-Beziehungen. Andere Beispiele sind solche wie zwischen Produkten und Kategorien - man dachte zun&auml;chst, dass es reicht, wenn man jedes Produkt nur einer Kategorie zuordnen kann, aber man dann erkennt, dass es f&uuml;r verschiedene Anwendungsf&auml;lle doch g&uuml;nstiger w&auml;re, wenn man ein Produkt mehr als einer Kategorie zuordnen kann. &Auml;hnliche F&auml;lle sind Mitarbeiter und Funktionen oder Abteilungen. In diesem Beitrag schauen wir uns das Beispiel eines Kunden an, der in seinem Sportverein partnerschaftliche Beziehungen &uuml;ber ein Fremdschl&uuml;sselfeld der Tabelle tblMitglieder auf diese selbst abgebildet hat. Hier gab es mehrere Gr&uuml;nde, um diese Beziehung in eine m:n-Beziehung umzuwandeln. Welche das sind und wie wir die Umwandlung durchgef&uuml;hrt haben, lesen Sie in diesem Beitrag.","og_url":"https:\/\/access-im-unternehmen.de\/Reflexive_1nBeziehung_zu_mnBeziehung\/","og_site_name":"Access im Unternehmen","article_published_time":"2026-02-06T13:37:56+00:00","og_image":[{"url":"http:\/\/vg01.met.vgwort.de\/na\/7bf4cb1679ba4ea685ab6870b1c08061","type":"","width":"","height":""}],"author":"Andr\u00e9 Minhorst","twitter_card":"summary_large_image","twitter_misc":{"Verfasst von":"Andr\u00e9 Minhorst","Gesch\u00e4tzte Lesezeit":"26\u00a0Minuten"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/access-im-unternehmen.de\/Reflexive_1nBeziehung_zu_mnBeziehung\/#article","isPartOf":{"@id":"https:\/\/access-im-unternehmen.de\/Reflexive_1nBeziehung_zu_mnBeziehung\/"},"author":{"name":"Andr\u00e9 Minhorst","@id":"https:\/\/access-im-unternehmen.de\/#\/schema\/person\/13395c4bcd7d7963efe33be9c584d93f"},"headline":"Reflexive 1:n-Beziehung zu m:n-Beziehung","datePublished":"2026-02-06T13:37:56+00:00","mainEntityOfPage":{"@id":"https:\/\/access-im-unternehmen.de\/Reflexive_1nBeziehung_zu_mnBeziehung\/"},"wordCount":4533,"commentCount":0,"publisher":{"@id":"https:\/\/access-im-unternehmen.de\/#organization"},"image":{"@id":"https:\/\/access-im-unternehmen.de\/Reflexive_1nBeziehung_zu_mnBeziehung\/#primaryimage"},"thumbnailUrl":"http:\/\/vg01.met.vgwort.de\/na\/7bf4cb1679ba4ea685ab6870b1c08061","articleSection":["1\/2026","2026","Tabellen und Datenmodellierung"],"inLanguage":"de","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/access-im-unternehmen.de\/Reflexive_1nBeziehung_zu_mnBeziehung\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/access-im-unternehmen.de\/Reflexive_1nBeziehung_zu_mnBeziehung\/","url":"https:\/\/access-im-unternehmen.de\/Reflexive_1nBeziehung_zu_mnBeziehung\/","name":"Reflexive 1:n-Beziehung zu m:n-Beziehung - Access im Unternehmen","isPartOf":{"@id":"https:\/\/access-im-unternehmen.de\/#website"},"primaryImageOfPage":{"@id":"https:\/\/access-im-unternehmen.de\/Reflexive_1nBeziehung_zu_mnBeziehung\/#primaryimage"},"image":{"@id":"https:\/\/access-im-unternehmen.de\/Reflexive_1nBeziehung_zu_mnBeziehung\/#primaryimage"},"thumbnailUrl":"http:\/\/vg01.met.vgwort.de\/na\/7bf4cb1679ba4ea685ab6870b1c08061","datePublished":"2026-02-06T13:37:56+00:00","breadcrumb":{"@id":"https:\/\/access-im-unternehmen.de\/Reflexive_1nBeziehung_zu_mnBeziehung\/#breadcrumb"},"inLanguage":"de","potentialAction":[{"@type":"ReadAction","target":["https:\/\/access-im-unternehmen.de\/Reflexive_1nBeziehung_zu_mnBeziehung\/"]}]},{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/access-im-unternehmen.de\/Reflexive_1nBeziehung_zu_mnBeziehung\/#primaryimage","url":"http:\/\/vg01.met.vgwort.de\/na\/7bf4cb1679ba4ea685ab6870b1c08061","contentUrl":"http:\/\/vg01.met.vgwort.de\/na\/7bf4cb1679ba4ea685ab6870b1c08061"},{"@type":"BreadcrumbList","@id":"https:\/\/access-im-unternehmen.de\/Reflexive_1nBeziehung_zu_mnBeziehung\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/access-im-unternehmen.de\/"},{"@type":"ListItem","position":2,"name":"Reflexive 1:n-Beziehung zu m:n-Beziehung"}]},{"@type":"WebSite","@id":"https:\/\/access-im-unternehmen.de\/#website","url":"https:\/\/access-im-unternehmen.de\/","name":"Access im Unternehmen","description":"Das Magazin f\u00fcr Datenbankentwickler auf Basis von Microsoft Access","publisher":{"@id":"https:\/\/access-im-unternehmen.de\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/access-im-unternehmen.de\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"de"},{"@type":"Organization","@id":"https:\/\/access-im-unternehmen.de\/#organization","name":"Andr\u00e9 Minhorst Verlag","url":"https:\/\/access-im-unternehmen.de\/","logo":{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/access-im-unternehmen.de\/#\/schema\/logo\/image\/","url":"https:\/\/access-im-unternehmen.de\/wp-content\/uploads\/2019\/09\/aiu_wp.png","contentUrl":"https:\/\/access-im-unternehmen.de\/wp-content\/uploads\/2019\/09\/aiu_wp.png","width":370,"height":111,"caption":"Andr\u00e9 Minhorst Verlag"},"image":{"@id":"https:\/\/access-im-unternehmen.de\/#\/schema\/logo\/image\/"}},{"@type":"Person","@id":"https:\/\/access-im-unternehmen.de\/#\/schema\/person\/13395c4bcd7d7963efe33be9c584d93f","name":"Andr\u00e9 Minhorst","image":{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/secure.gravatar.com\/avatar\/1b9d010cf1716692cb9c34f21554e07d17d461acaea5b61b8cb21cbec678d48a?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/1b9d010cf1716692cb9c34f21554e07d17d461acaea5b61b8cb21cbec678d48a?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/1b9d010cf1716692cb9c34f21554e07d17d461acaea5b61b8cb21cbec678d48a?s=96&d=mm&r=g","caption":"Andr\u00e9 Minhorst"}}]}},"_links":{"self":[{"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/posts\/55001587","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/comments?post=55001587"}],"version-history":[{"count":0,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/posts\/55001587\/revisions"}],"wp:attachment":[{"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/media?parent=55001587"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/categories?post=55001587"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/tags?post=55001587"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}