{"id":55000916,"date":"2013-12-01T00:00:00","date_gmt":"2020-05-22T21:32:06","guid":{"rendered":"http:\/\/access-im-unternehmen.aix-dev.de\/aiu\/?p=916"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-30T00:00:00","slug":"Datenmodelle_vergleichen","status":"publish","type":"post","link":"https:\/\/access-im-unternehmen.de\/Datenmodelle_vergleichen\/","title":{"rendered":"Datenmodelle vergleichen"},"content":{"rendered":"<p><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/vg07.met.vgwort.de\/na\/ce0afbfecae04000a32d87fcd3002db7\" width=\"1\" height=\"1\" alt=\"\"><\/p>\n<p><b>Sp&auml;testens dann, wenn Sie eine Datenbank zum Kunden geben, gibt es zwei Versionen der gleichen Datenbank. Meist geschieht dies bereits viel fr&uuml;her &#8211; zum Beispiel, wenn Sie eine Sicherheitskopie eines bestimmten Entwicklungsstands der Datenbank anfertigen, um ohne Sorge &auml;nderungen vornehmen zu k&ouml;nnen.  Was aber, wenn Sie etwa nach Arbeiten am Datenmodell noch einmal pr&uuml;fen m&ouml;chten, wie die Unterschiede zum Datenmodell einer anderen Version der Datenbank aussehen Genau: Dann hilft Ihnen die L&ouml;sung aus dem vorliegenden Beitrag weiter.<\/b><\/p>\n<p><b>Datenmodell &auml;ndern<\/b><\/p>\n<p>Es kann immer mal vorkommen, dass Sie unvorsichtigerweise &auml;nderungen am Datenmodell vornehmen. Sie sollten dann anschlie&szlig;end allerdings noch nachvollziehen k&ouml;nnen, welche &auml;nderungen dies waren. Aber wie das im Entwickleralltag so ist, ger&auml;t man in einem Programmierrausch und vergisst, die &auml;nderungen zu dokumentieren. Schwamm dr&uuml;ber: Wenn sich die M&ouml;glichkeit bietet, &auml;nderungen im Nachhinein durch einen Vergleich nachvollziehen zu k&ouml;nnen, kann man sich die Dokumentation doch sparen. Fehlt also nur noch ein geeignetes Tool, um die Datenmodelle zweier Datenbanken abzugleichen. Und dieses programmieren wir in diesem Beitrag.<\/p>\n<p><b>Vorgehensweise<\/b><\/p>\n<p>Es gibt verschiedene Vorgehensweisen f&uuml;r den Vergleich zweier Datenmodelle. Man k&ouml;nnte Tabelle f&uuml;r Tabelle, Feld f&uuml;r Feld und Eigenschaft f&uuml;r Eigenschaft durchlaufen und &auml;nderungen herausschreiben. Alternativ schreibt man erstmal den Status Quo der aktuellen und der urspr&uuml;nglichen Datenbank in Tabellen und vergleicht diese dann. In diesem Beitrag wollen wir die letztere Variante ausprobieren: Nach der Auswahl der Datenbanken sollen deren Informationen gleich in einem Satz von Tabellen landen. Nach dem Einlesen dieser Informationen f&uuml;r die betroffenen Datenbanken durchlaufen wir dann die angefallenen Daten. <\/p>\n<p><b>Die Anwendung im Einsatz<\/b><\/p>\n<p>Bild 1 zeigt das Formular der L&ouml;sung zu diesem Beitrag in der Formularansicht. Das Formular besteht aus den folgenden Elementen:<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2013_06\/pic_916_001.png\" alt=\"Die L&ouml;sung zum Vergleichen von Datenmodellen\" width=\"700\" height=\"379,8449\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 1: Die L&ouml;sung zum Vergleichen von Datenmodellen<\/span><\/b><\/p>\n<ul>\n<li>Das Textfeld <b>txtDatei1 <\/b>zeigt die erste der beiden zu vergleichenden Dateien an.<\/li>\n<li>Das Textfeld <b>txtDatei2 <\/b>arbeitet analog zum Textfeld <b>txtDatei1<\/b>.<\/li>\n<li>Die Schaltfl&auml;chen <b>cmdDatei1 <\/b>und <b>cmdDatei2 <\/b>rufen einen <b>Datei &ouml;ffnen<\/b>-Dialog aus und tragen den Pfad zur ausgew&auml;hlten Datei in die beiden Textfelder ein. Beide Schaltfl&auml;chen stellen nicht nur den Pfad in den Textfeldern ein, sondern lesen gleichzeitig auch bereits die Tabellen, Felder, Tabelleneigenschaften und Feldeigenschaften der ausgew&auml;hlten Datenbank ein.<\/li>\n<li>Mit dem Kontrollk&auml;stchen <b>ctlSystemtabellen <\/b>legt der Benutzer fest, ob Systemtabellen beim Einlesen ber&uuml;cksichtigt werden sollen.<\/li>\n<li>Mit dem Kontrollk&auml;stchen <b>ctlVersteckteTabellen <\/b>legt der Benutzer fest, ob als versteckt markierte Tabellen eingelesen werden sollen.<\/li>\n<li>Das Unterformular zeigt die Unterschiede zwischen den beiden Datenmodellen an.<\/li>\n<li>Die Schaltfl&auml;che <b>cmdVergleich <\/b>startet den Vergleich der beiden Datenmodelle und zeigt das Ergebnis im Unterformular an.<\/li>\n<\/ul>\n<p><b>Datenmodell der L&ouml;sung<\/b><\/p>\n<p>Das Datenmodell ist hierarchisch aufgebaut. Die oberste Ebene nimmt die die Tabelle <b>tblDatenbanken <\/b>ein, die aus den beiden Feldern <b>DatenbankID <\/b>und <b>Datenbank <\/b>besteht, wobei <b>Datenbank-ID <\/b>den Part des Prim&auml;rschl&uuml;sselfeldes &uuml;bernimmt (s. Bild 2).<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2013_06\/pic_916_002.png\" alt=\"Entwurf der Tabelle tblDatenbanken\" width=\"350\" height=\"86,15385\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 2: Entwurf der Tabelle tblDatenbanken<\/span><\/b><\/p>\n<p>Die Tabelle <b>tblTabellen <\/b>nimmt alle Tabellen der beiden beteiligten Datenbanken auf. Dazu stellt sie die Felder <b>TabelleID <\/b>als Prim&auml;rschl&uuml;sselfeld, <b>Tabelle <\/b>mit dem Tabellennamen sowie <b>Systemtabelle <\/b>und <b>VersteckteTabelle <\/b>als <b>Ja\/Nein<\/b>-Felder, die anzeigen, ob die Tabelle eine Systemtabelle oder eine versteckte Tabelle ist, zur Verf&uuml;gung. Au&szlig;erdem referenziert sie &uuml;ber das Fremdschl&uuml;sselfeld <b>Datenbank-ID <\/b>die Tabelle <b>tblDatenbanken<\/b> und legt somit fest, zu welcher Datenbank die Tabelle geh&ouml;rt (s. Bild 3).<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2013_06\/pic_916_003.png\" alt=\"Entwurf der Tabelle tblTabellen\" width=\"350\" height=\"127,1535\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 3: Entwurf der Tabelle tblTabellen<\/span><\/b><\/p>\n<p>Die einzelnen Felder einer jeden Tabelle speichert die Anwendung in der Tabelle <b>tblFelder <\/b>(s. Bild 4). Neben dem Prim&auml;rschl&uuml;sselfeld <b>FeldID <\/b>und dem Feld <b>Feld <\/b>zum Speichern des Feldnamens enth&auml;lt auch diese Tabelle wieder ein Fremdschl&uuml;sselfeld zum Herstellen der &uuml;bergeordneten Beziehung, in diesem Fall zur Tabelle <b>tblTabellen<\/b>.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2013_06\/pic_916_004.png\" alt=\"Entwurf der Tabelle tblFelder\" width=\"350\" height=\"87,99249\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 4: Entwurf der Tabelle tblFelder<\/span><\/b><\/p>\n<p>Nun fehlen noch die Eigenschaften der Tabelle sowie der einzelnen Felder. Diese speichert die Anwendung in zwei weiteren Tabellen. Die Tabelle <b>tblTabelleneigenschaften <\/b>speichert alle Eigenschaften der mit dem Fremdschl&uuml;sselfeld <b>TabelleID <\/b>referenzierten Tabelle aus <b>tblTabellen<\/b>, die Tabelle <b>tblFeldeigenschaften <\/b>erledigt das Gleiche f&uuml;r die Felder. Dabei enth&auml;lt die Tabelle <b>tblTabelleneigenschaften <\/b>neben dem Prim&auml;r- und dem Fremdschl&uuml;sselfeld noch zwei Felder namens <b>Tabelleneigenschaft <\/b>und <b>Eigenschaftswert <\/b>(s. Bild 5).<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2013_06\/pic_916_005.png\" alt=\"Entwurf der Tabelle tblTabelleneigenschaften\" width=\"350\" height=\"97,1136\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 5: Entwurf der Tabelle tblTabelleneigenschaften<\/span><\/b><\/p>\n<p>In der Tabelle <b>tblFeldeigenschaften <\/b>hei&szlig;en die entsprechenden Felder <b>Feldeigenschaft <\/b>und <b>Eigenschaftswert <\/b>(s. Bild 6).<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2013_06\/pic_916_006.png\" alt=\"Entwurf der Tabelle tblFeldeigenschaften\" width=\"350\" height=\"98,41714\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 6: Entwurf der Tabelle tblFeldeigenschaften<\/span><\/b><\/p>\n<p><b>Referenzielle Integrit&auml;t mit L&ouml;schweitergabe<\/b><\/p>\n<p>Im &uuml;berblick sieht das Datenmodell wie in Bild 7 aus. Wichtig ist an dieser Stelle, dass wir f&uuml;r alle Beziehungen zwischen den Tabellen referenzielle Integrit&auml;t mit L&ouml;schweitergabe definiert haben. Wenn die nachfolgenden Routinen dann einen Datensatz der Tabelle <b>tblDatenbanken <\/b>l&ouml;schen, um die Daten zu dieser Datenbank erneut einzulesen, entfernt Access automatisch auch die Daten aller damit verkn&uuml;pften Tabellen.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2013_06\/pic_916_007.png\" alt=\"Datenmodell der Anwendung in der &uuml;bersicht\" width=\"575\" height=\"232,338\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 7: Datenmodell der Anwendung in der &uuml;bersicht<\/span><\/b><\/p>\n<p><b>Optionen speichern<\/b><\/p>\n<p>Das Formular ist an die Tabelle <b>tblOptionen <\/b>gebunden. Diese enth&auml;lt Felder wie <b>Datei1<\/b>, <b>Datei2<\/b>, <b>SystemtabellenEinlesen <\/b>und <b>VersteckteTabellenEinlesen<\/b>. Die Textfelder <b>txtDatei1 <\/b>und <b>txtDatei2 <\/b>sowie die Kontrollk&auml;stchen <b>chkSystemtabellen <\/b>und <b>chkVersteckteTabellen <\/b>sind an diese Felder gebunden. Auf diese Weise merkt sich die L&ouml;sung die zuletzt verwendeten Einstellungen, was gerade beim Entwickeln einer solchen L&ouml;sung praktisch ist.<\/p>\n<p><b>Datenmodell einlesen<\/b><\/p>\n<p>Nachdem die Tabellen zum Erfassen der Elemente des Datenmodells, also Datenbanken, Tabellen, Felder, Tabelleneigenschaften und Feldeigenschaften, erstellt sind, k&ouml;nnen wir uns an die F&uuml;llung derselben begeben. Dies geht mit der Vorstellung einiger Details des Formulars <b>frmDatenmodellVergleichen <\/b>einher, das im Entwurf wie in Bild 8 aussieht.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2013_06\/pic_916_008.png\" alt=\"Das Formular frmDatenmodellVergleichen in der Entwurfsansicht\" width=\"575\" height=\"438,0592\"\/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 8: Das Formular frmDatenmodellVergleichen in der Entwurfsansicht<\/span><\/b><\/p>\n<p>Die Schaltfl&auml;che <b>cmdDatei1<\/b> ruft beim Anklicken die Prozedur aus Listing 1 auf. Diese Prozedur verwendet die Funktion <b>OpenFileName<\/b>, die Sie im Modul <b>mdlTools <\/b>der Datenbank finden, um einen <b>Datei &ouml;ffnen<\/b>-Dialog anzuzeigen, mit dem der Benutzer die erste der beiden zu vergleichenden Datenbanken ausw&auml;hlt. Wenn der Benutzer im Dialog die <b>Abbrechen<\/b>-Taste bet&auml;tigt, wird <b>Me!txtDatei <\/b>geleert. Die anschlie&szlig;ende Auswertung des Inhalts von <b>txtDatei1 <\/b>mit der <b>Dir<\/b>-Funktion und der Vergleich der L&auml;nge der ermittelten Zeichenkette liefert nur den Wert <b>True<\/b>, wenn es sich um eine g&uuml;ltige Datei handelt. Nur in diesem Fall ruft die Prozedur dann die Routine <b>DatenbankEinlesen <\/b>mit dem Pfad zur Datei als Parameter auf.<\/p>\n<p>Die zweite Schaltfl&auml;che <b>cmdDatei2 <\/b>arbeitet fast genauso &#8211; der einzige Unterschied ist, dass sie das Textfeld <b>txtDatei2 <\/b>f&uuml;llt.<\/p>\n<p><b>Datenbank einlesen<\/b><\/p>\n<p>Die Routine <b>DatenbankEinlesen<\/b>, die den Pfad zur einzulesenden Datenbank als Parameter erwartet, aktiviert zun&auml;chst die Sanduhr, da der Vorgang bereits f&uuml;r kleinere Datenmodelle ein paar Sekunden dauern kann (in aktuellen System erscheint nat&uuml;rlich l&auml;ngst keine Sanduhr mehr &#8211; aber Sie wissen ja, was gemeint ist). Die Prozedur deklariert zwei <b>Database<\/b>-Variablen: <b>db <\/b>referenziert die aktuelle Datenbank, um mit der <b>Execute<\/b>-Methode Datens&auml;tze zur Tabelle zum Speichern der Unterschiede hinzuf&uuml;gen zu k&ouml;nnen, <b>dbQuelle <\/b>referenziert die zu untersuchende Datenbank.<\/p>\n<p>Diese Datenbank &ouml;ffnet die Prozedur mit der <b>OpenDatabase<\/b>-Methode. Sie &uuml;bergibt dieser Methode den Pfad zur Datenbank sowie den Wert <b>True <\/b>f&uuml;r den Parameter <b>ReadOnly<\/b>. Dann l&ouml;scht sie alle Datens&auml;tze aus der Tabelle <b>tblDatenbanken<\/b>, deren Feld <b>Datenbank<\/b> den Pfad der hinzuzuf&uuml;genden Datenbank enth&auml;lt.<\/p>\n<p>Anschlie&szlig;end legt sie gleich einen entsprechenden neuen Datensatz in der Tabelle <b>tblDatenbanken <\/b>an und ermittelt mit der Abfrage <b>SELECT @@IDENTITY <\/b>den Prim&auml;rschl&uuml;sselwert des neu hinzuf&uuml;gten Datensatzes. Dieser wird sp&auml;ter zum Anlegen der Datens&auml;tze in der verkn&uuml;pften Tabelle <b>tblTabellen<\/b> ben&ouml;tigt. Der Aufruf der Routine <b>TabellenEinlesen <\/b>startet das Einlesen der Tabellen der soeben ge&ouml;ffneten Datenbank. Ist dieser Vorgang, der alle weiteren Aktionen anst&ouml;&szlig;t, abgeschlossen, l&auml;sst die Prozedur die Sanduhr wieder verschwinden.<\/p>\n<p><b>Tabellen einlesen<\/b><\/p>\n<p>Die Prozedur <b>TabellenEinlesen <\/b>erwartet Verweise auf die beiden betroffenen Datenbanken, also die aktuelle und die zu untersuchende Datenbank, sowie den Prim&auml;rschl&uuml;sselwert des zuvor in der Tabelle <b>tblDatenbanken <\/b>angelegten Datensatzes (s. Listing 3). Die Prozedur durchl&auml;uft in einer Schleife alle Elemente der <b>TableDefs<\/b>-Auflistung des mit <b>dbQuelle <\/b>referenzierten <b>Database<\/b>-Objekts. Dabei stellt sie jeweils zun&auml;chst die Variable <b>bolEinlesen <\/b>auf den Wert <b>True <\/b>ein und gibt einen Status &uuml;ber den aktuellen Bearbeitungsstand in der Statusleiste aus.<\/p>\n<p>Wenn Systemtabellen ignoriert werden sollen, die aktuell mit <b>tdf <\/b>referenzierte Tabelle aber eine Systemtabelle ist, wird <b>bolEinlesen <\/b>auf <b>False <\/b>eingestellt &#8211; das geschieht &auml;hnlich f&uuml;r versteckte <b>Tabellen<\/b>. Ob es sich um eine Systemtabelle oder um eine versteckte Tabelle handelt, erfahren wir durch einen Vergleich des Wertes der Eigenschaft <b>Attributes <\/b>der Tabelle mit dem Wert der Konstanten <b>dbSystemobject <\/b>beziehungsweise <b>dbHiddenObject<\/b>. Hat <b>bolEinlesen <\/b>anschlie&szlig;end noch den Wert <b>True<\/b>, f&uuml;gt die Prozedur der Tabelle <b>tblTabellen <\/b>einen entsprechenden Datensatz hinzu und speichert den Wert des Prim&auml;rschl&uuml;sselfeldes des neuen Datensatzes in der Variablen <b>lngTabelleID<\/b>. Anschlie&szlig;end ruft sie die beiden Prozeduren <b>FelderEinlesen <\/b>und <b>TabelleneigenschaftenEinlesen <\/b>auf.<\/p>\n<p><!--30percent--><\/p>\n<p><b>Felder einlesen<\/b><\/p>\n<p>Die erste der beiden genannten Prozeduren erwartet wiederum zwei Objektvariablen. Dabei handelt es sich wiederum um den Verweis auf die aktuelle Datenbank.<\/p>\n<p>Die Quelldatenbank ist diesmal nicht gefragt, denn wir ben&ouml;tigen ja Zugriff auf die Felder der &uuml;bergeordneten Tabelle. Daher &uuml;bergeben wir mit <b>tdf<\/b> einen Verweis auf das entsprechende <b>TableDef<\/b>-Objekt und au&szlig;erdem den Prim&auml;rschl&uuml;sselwert des zuvor angelegten Datensatzes der Tabelle <b>tblTabellen<\/b>.<\/p>\n<p>Die Prozedur <b>FelderAnlegen<\/b> durchl&auml;uft schlicht &uuml;ber die Variable <b>fld <\/b>die <b>Fields<\/b>-Auflistung des <b>TableDef<\/b>-Objekts <b>tdf<\/b>. Dabei aktualisiert sie wiederum die Statuszeile von Access, tr&auml;gt einen entsprechenden Datensatz in die Tabelle <b>tblFelder <\/b>ein, ermittelt den Prim&auml;rschl&uuml;sselwert des neuen Datensatzes und ruft dann die Prozedur auf, die sich um das Speichern der Eigenschaften der Felder k&uuml;mmert (s. Listing 4).<\/p>\n<p><b>Feldeigenschaften einlesen<\/b><\/p>\n<p>Die Prozedur FeldeigenschaftenEinlesen wird nun f&uuml;r jedes Feld einmal aufgerufen.<\/p>\n<p>Damit wir in der Statusmeldung einen Ausdruck der Form <b>Tabelle <Tabellenname>, Feld <Feldname>, Eigenschaft <Eigenschaftname> <\/b>ausgeben k&ouml;nnen, ben&ouml;tigt die Prozedur als Parameter zus&auml;tzlich zum Verweis auf die aktuelle Datenbank (<b>db<\/b>) Verweise auf das <b>TableDef<\/b>-Objekt und das <b>Field<\/b>-Objekt. Und nat&uuml;rlich darf der obligatorische Wert mit dem Prim&auml;rschl&uuml;sselwert des &uuml;bergeordneten Datensatzes aus der Tabelle <b>tblFelder <\/b>nicht fehlen (<b>lngFeldID<\/b>) &#8211; s. Listing 5.<\/p>\n<p>Die Prozedur durchl&auml;uft alle Elemente der <b>Properties<\/b>-Auflistung des <b>Field<\/b>-Objekts. Diesmal sollen ja nicht nur Namen gespeichert werden &#8211; wie bei der Datenbank, den Tabellen und den Feldern, &#8211; sondern die Bezeichnungen der Eigenschaften sowie die entsprechenden Werte. Bei den Eigenschaften des <b>Field<\/b>-Objekts gibt es die folgende Besonderheit: Das <b>Field<\/b>-Objekt kommt gleich an mehreren Stellen im <b>DAO<\/b>-Objektmodell vor. Allerdings werden nicht alle Eigenschaften des <b>Field<\/b>-Objekts, die &uuml;ber die <b>Properties<\/b>-Auflistung verf&uuml;gbar sind, in jedem Kontext genutzt.<\/p>\n<p>So fallen etwa beim <b>Field<\/b>-Objekt der <b>Fields<\/b>-Auflistung einer Tabelle die Eigenschaften <b>FieldSize<\/b>, <b>ForeignName<\/b>, <b>OriginalValue<\/b>, <b>ValidateOnSet<\/b>, <b>Value <\/b>und  <b>VisibleValue <\/b>unter den Tisch. Und nicht nur das: Wenn Sie versuchen, auf diese Eigenschaften &uuml;ber die <b>Properties<\/b>-Auflistung zuzugreifen, l&ouml;st dies einen Fehler aus. Also pr&uuml;fen wir vorab den Namen des aktuellen Elements der <b>Properties<\/b>-Auflistung in einer <b>Select Case<\/b>-Bedingung und ignorieren so die oben genannten Elemente.<\/p>\n<p>Schlie&szlig;lich schreibt die Prozedur f&uuml;r jede Eigenschaft des Tabellenfeldes einen neuen Datensatz in die Tabelle <b>tblFeldeigenschaften<\/b>. Den neuen Prim&auml;rschl&uuml;sselwert m&uuml;ssen wir uns nicht mehr merken, denn es gibt keine untergeordneten Elemente mehr.<\/p>\n<p><b>Tabelleneigenschaften einlesen<\/b><\/p>\n<p>Fehlt nur noch eine Art von Information: Die Eigenschaften der Tabellen selbst. Diese ermittelt die Prozedur <b>TabelleneigenschaftenEinlesen<\/b> aus Listing 6. Diese durchl&auml;uft wiederum alle <b>Property<\/b>-Elemente der <b>Properties<\/b>-Aufistung des <b>TableDef<\/b>-Objekts.<\/p>\n<p>Hier gibt es eine Besonderheit: Es kann n&auml;mlich vorkommen, dass Eigenschaften wie <b>NameMap <\/b>den Datentyp <b>dbLongBinary <\/b>aufweisen, deren Inhalt sich nicht so einfach in ein Textfeld schreiben l&auml;sst. Deshalb ignoriert die Prozedur nach einer Pr&uuml;fung auf <b>prp.Type = dbLongBinary <\/b>gleich komplett.<\/p>\n<p>Die Namen und Werte der Eigenschaften landen dann per <b>INSERT INTO<\/b>-Aktionsabfrage wie gewohnt in der Zieltabelle, in diesem Fall <b>tblTabelleneigenschaften<\/b>.<\/p>\n<p><b>Datenmodell vergleichen<\/b><\/p>\n<p>Um die durch die nachfolgend beschriebenen Prozeduren ermittelten Unterschiede zwischen den Datenmodellen der beiden Datenbanken zu speichern und diese schlie&szlig;lich im Unterformular <b>sfmDatenmodellVergleichen <\/b>anzuzeigen, m&uuml;ssen diese Informationen selbst in einer Tabelle gespeichert werden.<\/p>\n<p>Diese Tabelle hei&szlig;t <b>tblUnterschiede<\/b> und sieht im Entwurf wie in Bild 9 aus. Hier ist zu erl&auml;utern, dass es verschiedene Arten von Eintragungen geben wird, die Sie auch in Bild 10 wiederfinden: Wenn beispielsweise eine Tabelle in der einen Datenbank enthalten ist, in der anderen jedoch nicht, wird im Feld <b>Tabelle <\/b>der Tabellenname vermerkt. Je nachdem, ob die Tabelle in <b>Datenbank1 <\/b>oder in <b>Datenbank2 <\/b>vorliegt, wird in die entsprechenden Felder entweder der Eintrag <b>Vorhanden <\/b>oder <b>.\/. <\/b>eingetragen.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2013_06\/pic_916_009.png\" alt=\"Die Tabelle zum Speichern der Unterschiede zwischen den Datenmodellen\" width=\"400\" height=\"137,1841\"\/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 9: Die Tabelle zum Speichern der Unterschiede zwischen den Datenmodellen<\/span><\/b><\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2013_06\/pic_916_010.png\" alt=\"Einige Beispieldatens&auml;tze in der Tabelle tblUnterschiede\" width=\"650\" height=\"293,9073\"\/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 10: Einige Beispieldatens&auml;tze in der Tabelle tblUnterschiede<\/span><\/b><\/p>\n<p>Enth&auml;lt eine Tabelle ein Feld, das in der gleichnamigen Tabelle der anderen Datenbank nicht enthalten ist, landen Tabellen- und Feldname in den ersten beiden Feldern der Datenbank, die Felder <b>Datenbank1 <\/b>und <b>Datenbank2 <\/b>nehmen wiederum die Werte <b>Vorhanden <\/b>oder <b>.\/. <\/b>auf.<\/p>\n<p>Wenn sich die Werte einer Eigenschaft zweier gleichnamiger Tabellen unterscheiden, enth&auml;lt der entsprechende Datensatz den Namen der Tabelle und der Eigenschaft sowie die Eigenschaftswerte in den Feldern <b>Datenbank1 <\/b>und <b>Datenbank2<\/b>. Genauso sieht es bei den Eigenschaften von Tabellenfeldern aus &#8211; mit dem Unterschied, dass dann zus&auml;tzlich der Feldname in das Feld <b>Feld <\/b>eingetragen wird.<\/p>\n<p><b>Prozedur zum Vergleichen der Tabellen<\/b><\/p>\n<p>Die erste Prozedur wird durch das Bet&auml;tigen der Schaltfl&auml;che <b>cmdVergleichen <\/b>des Formulars <b>frmDatenmodellVergleichen <\/b>aufgerufen und sieht wie in Listing 7 aus. Die Prozedur leert die Tabelle <b>tblUnterschiede <\/b>und ermittelt dann per <b>DLookup <\/b>die Prim&auml;rschl&uuml;sselwerte der beiden zu vergleichenden Datenbanken.<\/p>\n<p>Der Vergleich der beiden Datenmodelle ist haupts&auml;tzlich auf den Einsatz von Abfragen statt auf VBA aufgebaut. Wir erl&auml;utern den Einsatz anhand der Abfragen zum Vergleichen der Tabellen der beiden Datenbanken.<\/p>\n<p>Und das funktioniert so: Wir verwenden zwei Abfragen namens <b>qryTabellenDatei1 <\/b>und <b>qryTabellenDatei2 <\/b>als Grundlage. Beide liefern exakt die Felder der Tabelle <b>tblTabellen<\/b>. Allerdings enth&auml;lt jeweils das Feld <b>DatenbankID <\/b>einen Parameter als Kriterium &#8211; <b>DatenbankID1 <\/b>bei der ersten, <b>DatenbankID2 <\/b>bei der zweiten Datenbank (s. Bild 11). Die eine Abfrage liefert also alle Tabellen der ersten Datenbank, die andere die der zweiten. Was fangen wir nun damit an Wir erstellen eine weitere Abfrage, welche die ersten beiden Abfragen aufnimmt (s. Bild 12). Die beiden Abfragen der Datenherkunft verkn&uuml;pfen wir dann &uuml;ber das Feld <b>Tabelle <\/b>miteinander. Dabei stellen Sie die Verkn&uuml;pfungseigenschaften so ein, dass auf jeden Fall alle Datens&auml;tze der ersten Abfrage angezeigt werden. Enth&auml;lt die zweite Abfrage keinen passenden Datensatz, soll die Abfrage hier einfach leere Felder liefern. Im aktuellen Zustand w&uuml;rde die Abfrage bei einer &uuml;berz&auml;hligen Tabelle in der ersten Datenbank zwar den Datensatz der Abfrage <b>qryTabellenDatei1 <\/b>liefern, aber keinen f&uuml;r die Abfrage <b>qryTabellenDatei2<\/b>. Das Feld <b>Tabelle <\/b>der zweiten Abfrage bliebe also leer. Und das machen wir uns zunutze: Wir pr&uuml;fen den Inhalt dieses Feldes per Kriterium gegen den Wert <b>Null<\/b>. Die Abfrage liefert also nur solche Tabellen-Datens&auml;tze, die in der ersten Datenbank vorkommen, aber nicht in der zweiten. Nun m&uuml;ssen wir nur noch Datens&auml;tze dieser Tabelle durchlaufen und jeweils einen Datensatz zur Tabelle <b>tblUnterschiede <\/b>hinzuf&uuml;gen. Das erledigen die folgenden Anweisungen der Prozedur <b>cmdVergleichen_Click<\/b>.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2013_06\/pic_916_012.png\" alt=\"Ermittlung aller Tabellen, die zwar in der ersten, nicht aber in der zweiten Datenbank enthalten sind\" width=\"625\" height=\"351,9652\"\/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 11: Ermittlung aller Tabellen, die zwar in der ersten, nicht aber in der zweiten Datenbank enthalten sind<\/span><\/b><\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2013_06\/pic_916_011.png\" alt=\"Diese Abfragen bilden die Grundlage zum Ermitteln von Tabellen, die nur in einer Datenbank vorkommen.\" width=\"625\" height=\"402,7778\"\/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 12: Diese Abfragen bilden die Grundlage zum Ermitteln von Tabellen, die nur in einer Datenbank vorkommen.<\/span><\/b><\/p>\n<p>Da die in der Abfrage <b>qryTabellenDatei1NichtDatei2 <\/b>Parameter enth&auml;lt, m&uuml;ssen wir diese zun&auml;chst per VBA f&uuml;llen. Dies erledigen wir, indem wir zun&auml;chst ein neues <b>QueryDef<\/b>-Objekt auf Basis dieser Abfrage erstellen.<\/p>\n<p>Dann legen wir nacheinander zwei <b>Parameter<\/b>-Objekte namens <b>prm <\/b>an und f&uuml;llen diese mit Verweisen auf die Namen der verwendeten Parameter, also <b>DatenbankID1 <\/b>und <b>DatenbankID2<\/b>. Dann f&uuml;llen wir die Parameter durch Zuweisung der in den Variablen <b>lngDatenbank1 <\/b>und <b>lngDatenbank2 <\/b>gespeicherten Werte an die Eigenschaft <b>Value <\/b>des Objekts <b>prm<\/b>. Wenn Sie nun die <b>OpenRecordset<\/b>-Methode des <b>QueryDef<\/b>-Objekts ausf&uuml;hren, erhalten Sie ein <b>Recordset-<\/b>Objekt mit allen gefundenen Datens&auml;tzen.<\/p>\n<p>Diese durchl&auml;uft die Prozedur in einer <b>Do While<\/b>-Schleife und f&uuml;gt f&uuml;r jeden Datensatz mit der <b>AddNew<\/b>-Methode einen neuen Datensatz zur Tabelle <b>tblUnterschiede <\/b>hinzu. Das Feld <b>Tabelle <\/b>erh&auml;lt den Namen der &uuml;berz&auml;hligen Tabelle, <b>Datenbank1 <\/b>wird mit <b>Vorhanden <\/b>und <b>Datenbank2 <\/b>mit <b>.\/. <\/b>gef&uuml;llt. Schlie&szlig;lich speichert die Prozedur den neuen Datensatz mit der <b>Update<\/b>-Methode.<\/p>\n<p>Auf die gleiche Weise m&uuml;ssen wir anschlie&szlig;end eigentlich auch bei den Tabellen vorgehen, die in der zweiten Datenbank vorhanden sind, aber nicht in der ersten. Die dazu ben&ouml;tigte Abfrage sieht wie in Bild 13 aus.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2013_06\/pic_916_013.png\" alt=\"Ermittlung aller Tabellen, die nur in der zweiten Datenbank enthalten sind\" width=\"400\" height=\"288,0659\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 13: Ermittlung aller Tabellen, die nur in der zweiten Datenbank enthalten sind<\/span><\/b><\/p>\n<p>Die Abfrage setzt die Verkn&uuml;pfungseigenschaften genau andersherum und gibt die beiden Felder <b>TabelleID <\/b>und <b>Tabelle <\/b>der Abfrage <b>qryTabellenDatei2 <\/b>der Datenherkunft aus.<\/p>\n<p>Die Codezeilen zum Durchlaufen dieser Abfrage und zum Anlegen der entsprechenden Datens&auml;tze in der Tabelle <b>tblUnterschiede <\/b>k&ouml;nnen analog zum Einlesen der Unterschiede aus dem vorherigen Teil erstellt werden.<\/p>\n<p><b>Optimierungsbedarf<\/b><\/p>\n<p>F&uuml;r diesen Vorgang, also das &ouml;ffnen eines Recordset mit Parametern und das anschlie&szlig;ende &uuml;bernehmen der gefundenen Daten in die Tabelle <b>tblUnterschiede<\/b>, haben wir nun rund 16 Zeilen Code ben&ouml;tigt. Das Gleiche geschieht nun nochmals f&uuml;r die Tabellen, die nur in der zweiten Datenbank enthalten sind.<\/p>\n<p>Au&szlig;erdem ben&ouml;tigen wir &auml;hnliche Konstrukte (inklusive entsprechender Abfragen), um zu ermitteln, welche Tabellen in beiden Datenbanken enthalten sind. Dieses Recordset wird dann die Grundlage f&uuml;r den Vergleich der weiteren Elemente und Eigenschaften sein &#8211; n&auml;mlich der Tabelleneigenschaften, Tabellenfelder und der Feldeigenschaften. Dies ist eine Menge Code, der sich erstens fast in gleicher Form st&auml;ndig wiederholt und der zweitens eine Menge DAO-Aktualisierungen innerhalb von <b>Do While<\/b>-Schleifen durchf&uuml;hrt. In den Beitr&auml;gen <b>Parameterabfragen unter der Lupe <\/b>(<b>www.access-im-unternehmen.de\/910<\/b>) und <b>Aktionsabfragen statt Schleifen <\/b>(<b>www.access-im-unternehmen.de\/911<\/b>) erfahren Sie, wie wir dies optimiert und auf wenige Zeilen Code reduziert haben.<\/p>\n<p>Auf diese Weise wird aus den 16 Zeilen ein Einzeiler mit einer ge&auml;nderten Abfrage und einer kleinen Hilfsfunktion.<\/p>\n<p><b>Gleichnamige Tabellen ermitteln<\/b><\/p>\n<p>Damit wir die Tabelleneigenschaften sowie die Tabellenfelder vergleichen k&ouml;nnen, m&uuml;ssen wir zun&auml;chst alle Tabellen ermitteln, die in beiden Datenbanken enthalten sind. Die dazu verwendete Abfrage nutzt wiederum die beiden Abfragen <b>qryTabellenDatei1 <\/b>und <b>qryTabellenDatei2 <\/b>als Datenherkunft.<\/p>\n<p>Sie sieht wie in Bild 14 aus und ermittelt alle Datens&auml;tze der beiden Herkunftsabfragen, deren Feld <b>Tabelle <\/b>den gleichen Wert enth&auml;lt. Davon gibt sie die Prim&auml;rschl&uuml;sselwerte aus sowie den Tabellennamen aus einer der beiden Abfragen &#8211; welche, ist egal, da die Werte ja ohnehin gleich sind. Wichtig ist, dass wir die Namen der Felder zur Ausgabe der <b>TabellenID <\/b>umbenennen, und zwar mit folgenden Ausdr&uuml;cken:<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2013_06\/pic_916_014.png\" alt=\"Ermittlung der gemeinsamen Tabellen der beiden Datenbanken\" width=\"400\" height=\"281,7121\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 14: Ermittlung der gemeinsamen Tabellen der beiden Datenbanken<\/span><\/b><\/p>\n<pre>TabelleID1: TabelleID\r\nTabelleID2: TabelleID<\/pre>\n<p>Auch f&uuml;r das Ergebnis dieser Abfrage holt die Prozedur sich ein Recordset und durchl&auml;uft alle Datens&auml;tze in einer <b>Do While<\/b>-Schleife. Darin ruft sie f&uuml;r jede Tabelle je einmal die Prozeduren <b>FelderVergleichen <\/b>und <b>TabelleneigenschaftenVergleichen <\/b>auf.<\/p>\n<p><b>Tabelleneigenschaften vergleichen<\/b><\/p>\n<p>Der Vergleich der Tabelleneigenschaften erfolgt etwas anders als der Abgleich der Tabellen, die nur in der einen oder in der anderen Datenbank enthalten sind.<\/p>\n<p>Der Grund ist, dass es ja nicht nur Eigenschaften gibt, die nur in einer der beiden Datenbanken enthalten sind, sondern auch solche, die zwar in einer Tabelle in beiden Datenbanken vorkommen, aber verschiedene Werte haben. Das hei&szlig;t, dass wir drei Vergleiche vornehmen m&uuml;ssen:<\/p>\n<ul>\n<li>Ermittlung aller Tabelleneigenschaften, die in der Tabelle in der ersten Datenbank vorkommen, aber nicht in der zweiten,<\/li>\n<li>Ermittlung aller Tabelleneigenschaften, die in der Tabelle in der zweiten Datenbank vorkommen, aber nicht in der ersten und<\/li>\n<li>Ermittlung aller Tabelleneigenschaften einer Tabelle, die in beiden Datenbanken vorkommen, aber unterschiedliche Werte enthalten.<\/li>\n<\/ul>\n<p>Dazu ben&ouml;tigen wir zun&auml;chst zwei Abfragen, welche die Eigenschaften der Tabelle aus der ersten und der aus der zweiten Datenbank liefern. Die erste sieht wie in Bild 15 aus.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2013_06\/pic_916_015.png\" alt=\"Ermittlung aller Eigenschaften einer Tabelle mit einem bestimmten Wert im Feld TabelleID\" width=\"575\" height=\"253,3641\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 15: Ermittlung aller Eigenschaften einer Tabelle mit einem bestimmten Wert im Feld TabelleID<\/span><\/b><\/p>\n<p>Das Ergebnis dieser Abfrage finden Sie am Beispiel der Tabelle <b>tblArtikel <\/b>in Bild 16.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2013_06\/pic_916_016.png\" alt=\"Eigenschaften einer Tabelle mit Werten\" width=\"400\" height=\"247,9532\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 16: Eigenschaften einer Tabelle mit Werten<\/span><\/b><\/p>\n<p>Die Abfrage <b>qryTabelleneigenschaftenDatei1NichtDatei2 <\/b>ermittelt nach bew&auml;hrter Manier die Eigenschaften, die nur die Tabelle in der ersten Datenbank enth&auml;lt, nicht aber die in der zweiten Datenbank, die Abfrage <b>qryTabelleneigenschaftenDatei2NichtDatei1 <\/b>erledigt dies f&uuml;r den umgekehrten Fall.<\/p>\n<p>Interessant ist die Abfrage <b>tblTabelleneigenschaftenVergleich<\/b>. Sie sieht wie in Bild 17 aus und enth&auml;lt die beiden Basisabfragen zur Ermittlung der Tabelleneigenschaften f&uuml;r die erste und die zweite Datenbank.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2013_06\/pic_916_017.png\" alt=\"Eigenschaften einer Tabelle in zwei Datenbanken vergleichen\" width=\"575\" height=\"230,7143\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 17: Eigenschaften einer Tabelle in zwei Datenbanken vergleichen<\/span><\/b><\/p>\n<p>Sie gibt den Namen der Eigenschaft sowie den Wert in der ersten und der zweiten Tabelle zur&uuml;ck. Dabei greift allerdings ein Kriterium, das nur diejenigen Datens&auml;tze zur&uuml;ckgibt, deren Wert im Feld <b>Eigenschaftswert <\/b>der ersten Tabelle nicht mit dem Wert im gleichen Feld der zweiten Tabelle &uuml;bereinstimmt. Die beiden Eigenschaftswerte werden dann als <b>Wert1 <\/b>und <b>Wert2 <\/b>ausgegeben.<\/p>\n<p>Die Prozedur <b>TabelleneigenschaftenVergleichen <\/b>aus Listing 8 verwendet gegen&uuml;ber der Art und Weise, wie wir in <b>cmdVergleichen_Click <\/b>vorgegangen sind, bereits eine verbesserte Version.<\/p>\n<p>Sie erstellt zun&auml;chst mithilfe der Funktion <b>RecordsetAusParameterabfrage<\/b>, die im Beitrag <b>Parameterabfragen unter der Lupe <\/b>(<b>www.access-im-unternehmen.de\/910<\/b>) erl&auml;utert wird, drei Recordsets auf Basis der Abfragen <b>qryTabelleneigenschaftenDatei1NichtDatei2<\/b>, <b>qryTabelleneigenschaftenDatei2NichtDatei1 <\/b>und <b>qryTabelleneigenschaften <\/b>und durchl&auml;uft diese in <b>Do While<\/b>-Schleifen. Darin schreibt sie, ebenfalls in einer Weiterentwicklung der zuvor genutzten <b>DAO<\/b>-Befehle <b>AddNew <\/b>und <b>Update<\/b>, mit einer per <b>Execute <\/b>ausgef&uuml;hrten <b>INSERT INTO<\/b>-Abfrage die gefundenen Daten in die Tabelle <b>tblUnterschiede<\/b>.<\/p>\n<p><b>Felder vergleichen<\/b><\/p>\n<p>Nun folgen die Felder. Diese vergleichen wir in der Prozedur <b>FelderVergleichen <\/b>zun&auml;chst anhand des Namens. Die Prozedur <b>FelderVergleichen <\/b>erwartet einen Verweis auf das <b>Database<\/b>-Objekt, den Prim&auml;rschl&uuml;sselwert f&uuml;r die Tabelle der ersten und f&uuml;r die der zweiten Datenbank sowie den Namen der Tabelle als Parameter.<\/p>\n<p>Hier finden Sie einen weiteren Evolutionsschritt vor: Statt der langwierigen Ermittlung des Recordsets auf Basis einer Parameterabfrage und dem anschlie&szlig;enden Durchlaufen des Recordsets, um die Unterschiede in die Tabelle <b>tblUnterschiede <\/b>einzutragen, finden Sie hier nur noch den Aufruf einer einzigen Prozedur namens <b>AktionsabfragenMitParameter<\/b>. Dazu ist auch die Erstellung von Aktionsabfragen statt Auswahlabfragen n&ouml;tig, aber dies besprechen wir im Beitrag <b>Aktionsabfragen statt Schleifen <\/b>(<b>www.access-im-unternehmen.de\/911<\/b>).<\/p>\n<p>Die Felder einer Tabelle werden &auml;hnlich abgeglichen wie die Tabellen einer Datenbank weiter oben: Wir erstellen je eine Abfrage, die alle Felder ermittelt, die in der Tabelle der ersten Datenbank vorkommen, aber nicht in der zweiten und umgekehrt. Diesmal verwenden wir allerdings direkt eine Aktionsabfrage und f&uuml;hren diese aus.<\/p>\n<p>Au&szlig;erdem ben&ouml;tigen wir noch eine Auswahlabfrage, die alle Felder liefert, die in beiden Versionen der aktuell zu untersuchenden Tabelle vorkommen.<\/p>\n<p>Zu diesen legen wir zun&auml;chst keine Daten in der Tabelle <b>tblUnterschiede <\/b>an, aber wir rufen zu jedem dieser Felder die Prozedur <b>FeldeigenschaftenVergleichen <\/b>auf. Und diese vergleicht, genau wie bereits bei den Tabelleneigenschaften, die Eigenschaften der einzelnen Felder miteinander.<\/p>\n<p><b>Feldeigenschaften vergleichen<\/b><\/p>\n<p>Der letzte Vergleich bezieht sich auf die einzelnen Feldeigenschaften. Dazu geh&ouml;rt beispielsweise auch der Felddatentyp. Auch f&uuml;r diesen Vergleich erstellen wir wieder zwei Abfragen, welche die Eigenschaften erfassen, die in der ersten, aber nicht in der zweiten Datenbank enthalten sind und umgekehrt. Diese hei&szlig;en nun <b>qryFeldeigenschaftenDatei1 <\/b>und <b>qryFeldeigenschaftenDatei2<\/b>.<\/p>\n<p>Auf Basis dieser beiden Abfragen erstellen wir drei Aktionsabfragen (wir wollen diesmal eine h&ouml;here Evolutionsstufe wie in <b>Aktionsabfragen statt Schleifen <\/b>(<b>www.access-im-unternehmen.de\/911<\/b>) beschrieben erklimmen).<\/p>\n<p>Die erste Abfrage, die alle Feldeigenschaften eines Feldes der ersten Datenbank liefern soll, die nicht in der zweiten Datenbank enthalten sind, sieht wie in Bild 18 aus. Da wir auch den Tabellennamen und den Feldnamen in die Tabelle <b>tblUnterschiede <\/b>eintragen wollen, haben wir gegen&uuml;ber den vorherigen Abfragen noch die beiden Tabellen <b>tblTabellen <\/b>und <b>tblFelder <\/b>hinzugef&uuml;gt. Diese liefern mit den Feldern <b>Tabelle <\/b>und <b>Feld <\/b>die fehlenden Werte. Diese Felder werden, wie bei einer Anf&uuml;ge- oder <b>INSERT INTO<\/b>-Abfrage &uuml;blich, dem Zielfeld zugewiesen. Gleiches geschieht mit dem Feld <b>Feldeigenschaft<\/b>. Als Eigenschaftswerte verwenden wir den Wert des Feldes <b>Eigenschaftswert <\/b>der Abfrage <b>qryFeldeigenschaftenDatei1 <\/b>sowie den Ausdruck <b>.\/. <\/b>f&uuml;r die Datenbank, in der die entsprechende Eigenschaft nicht verwendet wird. In der Abfrage <b>qryINSERTINTOFeldeigenschaftenDatei2NichtDatei1 <\/b>sieht es umgekehrt aus.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2013_06\/pic_916_018.png\" alt=\"Aktionsabfrage zum Einf&uuml;gen aller Feldeigenschaften in die Tabelle tblUnterschiede, die in einem Feld der ersten Datenbank vorkommen, aber nicht in der zweiten.\" width=\"650\" height=\"237,1906\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 18: Aktionsabfrage zum Einf&uuml;gen aller Feldeigenschaften in die Tabelle tblUnterschiede, die in einem Feld der ersten Datenbank vorkommen, aber nicht in der zweiten.<\/span><\/b><\/p>\n<p>Schlie&szlig;lich schreibt die Prozedur <b>FeldeigenschaftenVergleichen<\/b> die ermittelten Unterschiede in die Tabelle <b>tblUnterschiede<\/b>. Dabei verwendet sie lediglich drei Aufrufe einer weiteren Hilfsfunktion namens <b>AktionsabfrageMitParameter<\/b>, die Sie wiederum im Beitrag <b>Parameterabfragen unter der Lupe <\/b>(<b>www.access-im-unternehmen.de\/910<\/b>) kennenlernen.<\/p>\n<p>Die zuerst aufgerufene Prozedur <b>cmdVergleichen_Click <\/b>aktualisiert schlie&szlig;lich das Unterformular mit dem Inhalt der Tabelle <b>tblUnterschiede<\/b>.<\/p>\n<p><b>Zusammenfassung und Ausblick<\/b><\/p>\n<p>Die aktuelle Version von <b>amvDatenmodellVergleichen<\/b> liefert bereits hilfreiche Informationen, wenn es um den Vergleich verschiedener Versionen einer Datenbank geht. Man k&ouml;nnte dies noch erweitern, indem man Beziehungen und Indizes hinzunimmt oder den Eigenschaften wie dem Felddatentyp, der nur in Form einer Zahl gespeichert wird, den Namen der entsprechenden Konstanten zuweist.<\/p>\n<h3>Downloads zu diesem Beitrag<\/h3>\n<p>Enthaltene Beispieldateien:<\/p>\n<p>DatenmodellVergleichen.mdb<\/p>\n<p><a href=\"..\/fileadmin\/beispiele\/{A516B110-B8CB-485D-A479-FF96DCB70358}\/aiu_916.zip\">Download<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Sp&auml;testens dann, wenn Sie eine Datenbank zum Kunden geben, gibt es zwei Versionen der gleichen Datenbank. Meist geschieht dies bereits viel fr&uuml;her &#8211; zum Beispiel, wenn Sie eine Sicherheitskopie eines bestimmten Entwicklungsstands der Datenbank anfertigen, um ohne Sorge &Auml;nderungen vornehmen zu k&ouml;nnen.  Was aber, wenn Sie etwa nach Arbeiten am Datenmodell noch einmal pr&uuml;fen m&ouml;chten, wie die Unterschiede zum Datenmodell einer anderen Version der Datenbank aussehen Genau: Dann hilft Ihnen die L&ouml;sung aus dem vorliegenden Beitrag weiter.<\/b><\/p>\n<p><b>Datenmodell &auml;ndern<\/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":[662013,66062013,44000027],"tags":[],"class_list":["post-55000916","post","type-post","status-publish","format-standard","hentry","category-662013","category-66062013","category-Loesungen"],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v20.9 (Yoast SEO v27.5) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>Datenmodelle vergleichen - 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\/Datenmodelle_vergleichen\/\" \/>\n<meta property=\"og:locale\" content=\"de_DE\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Datenmodelle vergleichen\" \/>\n<meta property=\"og:description\" content=\"Sp&auml;testens dann, wenn Sie eine Datenbank zum Kunden geben, gibt es zwei Versionen der gleichen Datenbank. Meist geschieht dies bereits viel fr&uuml;her - zum Beispiel, wenn Sie eine Sicherheitskopie eines bestimmten Entwicklungsstands der Datenbank anfertigen, um ohne Sorge &Auml;nderungen vornehmen zu k&ouml;nnen. Was aber, wenn Sie etwa nach Arbeiten am Datenmodell noch einmal pr&uuml;fen m&ouml;chten, wie die Unterschiede zum Datenmodell einer anderen Version der Datenbank aussehen Genau: Dann hilft Ihnen die L&ouml;sung aus dem vorliegenden Beitrag weiter. Datenmodell &auml;ndern\" \/>\n<meta property=\"og:url\" content=\"https:\/\/access-im-unternehmen.de\/Datenmodelle_vergleichen\/\" \/>\n<meta property=\"og:site_name\" content=\"Access im Unternehmen\" \/>\n<meta property=\"article:published_time\" content=\"2020-05-22T21:32:06+00:00\" \/>\n<meta property=\"og:image\" content=\"http:\/\/vg07.met.vgwort.de\/na\/ce0afbfecae04000a32d87fcd3002db7\" \/>\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=\"21\u00a0Minuten\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Datenmodelle_vergleichen\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Datenmodelle_vergleichen\\\/\"},\"author\":{\"name\":\"Andr\u00e9 Minhorst\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#\\\/schema\\\/person\\\/13395c4bcd7d7963efe33be9c584d93f\"},\"headline\":\"Datenmodelle vergleichen\",\"datePublished\":\"2020-05-22T21:32:06+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Datenmodelle_vergleichen\\\/\"},\"wordCount\":4305,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#organization\"},\"image\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Datenmodelle_vergleichen\\\/#primaryimage\"},\"thumbnailUrl\":\"http:\\\/\\\/vg07.met.vgwort.de\\\/na\\\/ce0afbfecae04000a32d87fcd3002db7\",\"articleSection\":[\"2013\",\"6\\\/2013\",\"L\u00f6sungen\"],\"inLanguage\":\"de\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/access-im-unternehmen.de\\\/Datenmodelle_vergleichen\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Datenmodelle_vergleichen\\\/\",\"url\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Datenmodelle_vergleichen\\\/\",\"name\":\"Datenmodelle vergleichen - Access im Unternehmen\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Datenmodelle_vergleichen\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Datenmodelle_vergleichen\\\/#primaryimage\"},\"thumbnailUrl\":\"http:\\\/\\\/vg07.met.vgwort.de\\\/na\\\/ce0afbfecae04000a32d87fcd3002db7\",\"datePublished\":\"2020-05-22T21:32:06+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Datenmodelle_vergleichen\\\/#breadcrumb\"},\"inLanguage\":\"de\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/access-im-unternehmen.de\\\/Datenmodelle_vergleichen\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Datenmodelle_vergleichen\\\/#primaryimage\",\"url\":\"http:\\\/\\\/vg07.met.vgwort.de\\\/na\\\/ce0afbfecae04000a32d87fcd3002db7\",\"contentUrl\":\"http:\\\/\\\/vg07.met.vgwort.de\\\/na\\\/ce0afbfecae04000a32d87fcd3002db7\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Datenmodelle_vergleichen\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/access-im-unternehmen.de\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Datenmodelle vergleichen\"}]},{\"@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":"Datenmodelle vergleichen - 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\/Datenmodelle_vergleichen\/","og_locale":"de_DE","og_type":"article","og_title":"Datenmodelle vergleichen","og_description":"Sp&auml;testens dann, wenn Sie eine Datenbank zum Kunden geben, gibt es zwei Versionen der gleichen Datenbank. Meist geschieht dies bereits viel fr&uuml;her - zum Beispiel, wenn Sie eine Sicherheitskopie eines bestimmten Entwicklungsstands der Datenbank anfertigen, um ohne Sorge &Auml;nderungen vornehmen zu k&ouml;nnen. Was aber, wenn Sie etwa nach Arbeiten am Datenmodell noch einmal pr&uuml;fen m&ouml;chten, wie die Unterschiede zum Datenmodell einer anderen Version der Datenbank aussehen Genau: Dann hilft Ihnen die L&ouml;sung aus dem vorliegenden Beitrag weiter. Datenmodell &auml;ndern","og_url":"https:\/\/access-im-unternehmen.de\/Datenmodelle_vergleichen\/","og_site_name":"Access im Unternehmen","article_published_time":"2020-05-22T21:32:06+00:00","og_image":[{"url":"http:\/\/vg07.met.vgwort.de\/na\/ce0afbfecae04000a32d87fcd3002db7","type":"","width":"","height":""}],"author":"Andr\u00e9 Minhorst","twitter_card":"summary_large_image","twitter_misc":{"Verfasst von":"Andr\u00e9 Minhorst","Gesch\u00e4tzte Lesezeit":"21\u00a0Minuten"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/access-im-unternehmen.de\/Datenmodelle_vergleichen\/#article","isPartOf":{"@id":"https:\/\/access-im-unternehmen.de\/Datenmodelle_vergleichen\/"},"author":{"name":"Andr\u00e9 Minhorst","@id":"https:\/\/access-im-unternehmen.de\/#\/schema\/person\/13395c4bcd7d7963efe33be9c584d93f"},"headline":"Datenmodelle vergleichen","datePublished":"2020-05-22T21:32:06+00:00","mainEntityOfPage":{"@id":"https:\/\/access-im-unternehmen.de\/Datenmodelle_vergleichen\/"},"wordCount":4305,"commentCount":0,"publisher":{"@id":"https:\/\/access-im-unternehmen.de\/#organization"},"image":{"@id":"https:\/\/access-im-unternehmen.de\/Datenmodelle_vergleichen\/#primaryimage"},"thumbnailUrl":"http:\/\/vg07.met.vgwort.de\/na\/ce0afbfecae04000a32d87fcd3002db7","articleSection":["2013","6\/2013","L\u00f6sungen"],"inLanguage":"de","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/access-im-unternehmen.de\/Datenmodelle_vergleichen\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/access-im-unternehmen.de\/Datenmodelle_vergleichen\/","url":"https:\/\/access-im-unternehmen.de\/Datenmodelle_vergleichen\/","name":"Datenmodelle vergleichen - Access im Unternehmen","isPartOf":{"@id":"https:\/\/access-im-unternehmen.de\/#website"},"primaryImageOfPage":{"@id":"https:\/\/access-im-unternehmen.de\/Datenmodelle_vergleichen\/#primaryimage"},"image":{"@id":"https:\/\/access-im-unternehmen.de\/Datenmodelle_vergleichen\/#primaryimage"},"thumbnailUrl":"http:\/\/vg07.met.vgwort.de\/na\/ce0afbfecae04000a32d87fcd3002db7","datePublished":"2020-05-22T21:32:06+00:00","breadcrumb":{"@id":"https:\/\/access-im-unternehmen.de\/Datenmodelle_vergleichen\/#breadcrumb"},"inLanguage":"de","potentialAction":[{"@type":"ReadAction","target":["https:\/\/access-im-unternehmen.de\/Datenmodelle_vergleichen\/"]}]},{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/access-im-unternehmen.de\/Datenmodelle_vergleichen\/#primaryimage","url":"http:\/\/vg07.met.vgwort.de\/na\/ce0afbfecae04000a32d87fcd3002db7","contentUrl":"http:\/\/vg07.met.vgwort.de\/na\/ce0afbfecae04000a32d87fcd3002db7"},{"@type":"BreadcrumbList","@id":"https:\/\/access-im-unternehmen.de\/Datenmodelle_vergleichen\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/access-im-unternehmen.de\/"},{"@type":"ListItem","position":2,"name":"Datenmodelle vergleichen"}]},{"@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\/55000916","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=55000916"}],"version-history":[{"count":0,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/posts\/55000916\/revisions"}],"wp:attachment":[{"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/media?parent=55000916"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/categories?post=55000916"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/tags?post=55000916"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}