Daten zusammenführen per Formular

Wenn Sie mit Duplikaten arbeiten oder Daten aus mehreren Datenbanken zusammenführen möchten, kann ein Formular zum Abgleich ähnlicher Datensätze hilfreich sein. Dieses sollte die relevanten Felder beider Datensätze nebeneinanderstellen und dem Benutzer die Möglichkeit bieten, die Daten des einen, des anderen oder auch beider Datensätze in einen Datensatz zu überführen. Dieser Beitrag zeigt, wie Sie ein solches Formular erstellen und damit Datensätze abgleichen.

Das gewünschte Formular soll wie in Bild 1 aussehen und jeweils die Feldnamen, die Werte der Zieltabelle und die Werte der Quelltabelle anzeigen. Der Benutzer soll alle Felder der Quelltabelle, alle Felder der Zieltabelle oder auch eine Mischung der Daten aus beiden Datensätzen auswählen können. Dies ist bereits die erste Hürde: Wie stellt man dies dar beziehungsweise welche Steuerelemente verwenden wir dafür

pic001.png

Bild 1: Das Formular zum Abgleichen von Datensätzen

Die naheliegendste Lösung wäre wohl gewesen, eine Reihe von Textfeldern nebeneinander zu platzieren und diese je nach Datenherkunft zu füllen. Diesmal haben wir uns jedoch für das Listenfeld entschieden – allein, weil es durch die mögliche Mehrfachmarkierung bereits eine wichtige Funktion mitbringt. Genau genommen sind es drei Listenfelder, die im Formular frmAbgleichDetails ihren Dienst tun. Das erste enthält die Feldnamen, das zweite die Daten der Zieltabelle und das dritte die Daten der Quelltabelle. Ganz oben befindet sich noch ein Eintrag, mit dem der Benutzer per Mausklick alle Felder einer Spalte auswählen können soll.

Bevor wir auf die technischen Feinheiten dieser Lösung eingehen, schauen wir uns an, wie Sie das Formular einsetzen können. Der Aufruf erfordert nämlich eine Reihe von Informationen, die Sie dem Formular über das Öffnungsargument OpenArgs übergeben. Der Aufruf sieht beispielsweise wie folgt aus:

DoCmd.OpenForm "frmAbgleichDetails", _
OpenArgs:="LieferantID|LieferantID|1|77|tblLieferanten|tblLieferanten1|LieferantID;
Firma;Kontaktperson;Position;Strasse;Ort;Region;PLZ;
Land;Telefon;Telefax;Homepage", WindowMode:=acDialog

Wenn wir uns den Wert für OpenArgs allein ansehen, sieht das Ganze schon übersichtlicher aus:

LieferantID|LieferantID|1|77|tblLieferanten|tblLieferanten1|LieferantID;Firma;
Kontaktperson;Position;Strasse;Ort;Region;PLZ;Land;Telefon;Telefax;Homepage

Dort gibt es zunächst eine ganze Reihe von Informationen, die durch das Pipe-Zeichen voneinander getrennt werden. Dabei handelt es sich um die folgenden:

  • Primärschlüsselfeld der Zieltabelle
  • Primärschlüsselfeld der Quelltabelle
  • Wert des Primärschlüsselfeldes des Zieldatensatzes
  • Wert des Primärschlüsselfeldes des Quelldatensatzes
  • Name der Zieltabelle
  • Name der Quelltabelle
  • Semikolon-separierte Liste der Felder, die angezeigt werden sollen

Erst wenn Sie für diese sieben Parameter sinnvolle Werte übergeben, zeigt das Formular die Daten zum Abgleich an.

Im vorliegenden Fall soll es den Datensatz mit dem Primärschlüsselwert 1 der Zieltabelle tblLieferanten und den Datensatz mit dem Primärschlüsselwert 77 der (in einer anderen Datenbank befindlichen und verknüpften) Quelltabelle tblLieferanten1 anzeigen, und davon die Felder LieferantID, Firma, Kontaktperson, Position, Strasse, Ort, Region, PLZ, Land, Telefon, Telefax und Homepage.

Nach diesem Aufruf erscheint das Formular und zeigt den gewünschten Datensatz an. Sie können nun die Feldinhalte auswählen und das Formular mit einem Klick auf die Schaltfläche OK schließen. Das Formular übernimmt nur die Darstellung und Markierung der gewünschten Daten, den Code zum Auslesen der gewählten Daten müssen Sie wie die Anweisung zum Öffnen des Formulars selbst bereitstellen.

In einem einfachen Beispiel sieht das wie in Listing 1 aus. Hier werden die beiden zu vergleichenden Datensatzgruppen geöffnet und per Recordset-Variable referenziert. Die Prozedur durchläuft die Datensätze der Quelltabelle und prüft, ob es in der Zieltabelle bereits einen Datensatz mit dem gleichen Wert im Feld Firma gibt. Falls nicht, wird der Datensatz zur Zieltabelle hinzugefügt, falls doch, tritt unser Formular für den Datenabgleich auf den Plan.

Listing 1: Abgleich zweier Datensätze mit Untersuchung im Formular durchführen

Public Sub DatenZusammenfuehren_Lieferanten_MitAbgleich()
    Dim db As DAO.Database
    Dim rstQuelle As DAO.Recordset, rstZiel As DAO.Recordset
    Dim lngZielID As Long
    Set db = CurrentDb
    Set rstQuelle = db.OpenRecordset("SELECT * FROM tblLieferanten1", dbOpenDynaset)
    Set rstZiel = db.OpenRecordset("SELECT * FROM tblLieferanten", dbOpenDynaset)
    db.Execute "DELETE FROM tblPKAltUndNeu", dbFailOnError
    Do While Not rstQuelle.EOF
     lngZielID = Nz(DLookup("LieferantID", "tblLieferanten", "Firma = ''" _
            & Replace(rstQuelle!Firma, "''", "''''") & "''"))
        If lngZielID = 0 Then
            rstZiel.AddNew
            rstZiel!Firma = rstQuelle!Firma
            ''... weitere Felder
            lngZielID = rstZiel!LieferantID
            rstZiel.Update
        Else
            DoCmd.Close acForm, "frmAbgleichDetails"
            DoCmd.OpenForm "frmAbgleichDetails", OpenArgs:="LieferantID|LieferantID|" & lngZielID _
                & "|" & rstQuelle!LieferantID & "|tblLieferanten|tblLieferanten1|LieferantID;" _
                & "Firma;Kontaktperson;Position;Strasse;Ort;Region;PLZ;Land;Telefon;Telefax;" _
                & "Homepage", windowMode:=acDialog
            If mdlTools_Abgleich.IstFormularGeoeffnet("frmAbgleichDetails") Then
                rstZiel.FindFirst "LieferantID = " & lngZielID
                rstZiel.Edit
                rstZiel!Firma = Forms!frmAbgleichDetails.Wert("Firma")
                rstZiel!Kontaktperson = Forms!frmAbgleichDetails.Wert("Kontaktperson")
                ''... weitere Felder
                lngZielID = Forms!frmAbgleichDetails.Wert("LieferantID")
                rstZiel.Update
                DoCmd.Close acForm, "frmAbgleichDetails"
            End If
        End If
        rstQuelle.MoveNext
    Loop
    Set db = Nothing
End Sub

In diesem Fall wird dieses mit einigen variablen Parametern geöffnet, namentlich den Primärschlüsselfeldern der beiden zu vergleichenden Datensätze, die ja mit jedem Satz zu vergleichender Datensätze wechseln. Der Primärschlüsselwert des Zieldatensatzes wurde dazu bereits vorher in der Variablen lngZielID gespeichert, der Quelldatensatzwert wird direkt aus dem Datensatz eingelesen.

Nun öffnet sich das Formular und der Benutzer legt fest, welches Feld mit welchem Wert der beiden Datensätze gefüllt werden soll. Danach klickt er auf OK und sorgt dafür, dass das Formular unsichtbar wird und somit den Fokus verliert.

Da es als modaler Dialog geöffnet wurde, läuft die aufrufende Prozedur erst jetzt weiter. Nach einer Prüfung, ob das Formular frmAbgleichDetails noch geöffnet ist, werden die Daten entsprechend den Angaben im Formular in den Zieldatensatz geschrieben. Das unsichtbare, aber noch nicht geschlossene Formular bietet eine Funktion namens Wert an, die den Namen eines Feldes erwartet und den ausgewählten Wert zurückliefert.

Die Prozedur sucht den Zieldatensatz aus der Datensatzgruppe heraus und schreibt die im Formular ausgewählten Werte in die jeweiligen Felder des Datensatzes.

Nach dem Aktualisieren des Datensatzes wird das Formular nun endgültig geschlossen und der nächste Datensatz der Quelltabelle wird untersucht. Wenn alle Datensätze durchlaufen wurden, ist der Vorgang abgeschlossen.

Aufbau des Formulars

Schauen wir uns nun an, was dafür sorgt, dass Sie mit dem Formular so komfortabel die Werte für den Zieldatensatz auswählen können. Die erste bemerkenswerte Tatsache ist, dass es dort scheinbar drei Listenfelder gibt, durch die Sie mit einer einzigen Bildlaufleiste scrollen können. Wie funktioniert das Nun, es ist ganz einfach: Die drei Listenfelder befinden sich in einem Unterformular, das die Bildlaufleiste bereitstellt.

Damit immer alle Felder der beiden Tabellen in die Listenfelder passen, haben wir diese ausreichend hoch dimensioniert – und bei Bedarf können Sie die Größe auch noch selbst anpassen.

Bild 2 zeigt das Unterformular mit den drei Listenfeldern lstFelder, lstZieltabelle und lstQuelltabelle.

pic003.png

Bild 3: Aufbau des gesamten Formulars mit Unterformular und Listenfeldern

Die beiden rechten Listenfelder sollen die Mehrfachauswahl ermöglichen, daher stellen Sie die Eigenschaft Mehrfachauswahl auf Einzeln ein.

Das linke Listenfeld soll nur die Zeilenbeschriftungen mit den Feldnamen stellen. Daher stellen wir seine Eigenschaft Rahmenart auf Transparent ein.

Alle drei Listenfelder beziehen ihre Daten später aus Wertlisten, die beim Öffnen des Formulars zusammengestellt werden. Stellen Sie daher die Eigenschaft Herkunftsart der drei Listenfelder jeweils auf den Wert Wertliste ein.

Bild 3 stellt dar, wie das Unterformular mit den drei Listenfeldern in das Hauptformular integriert wird. Neben dem Unterformular finden Sie dort einige Beschriftungsfelder sowie Schaltflächen. Deren Bedeutung betrachten wir später.

pic002.png

Bild 2: Unterformular mit den Listenfeldern zur Anzeige der abzugleichenden Daten

Listenfelder füllen

Die erste Aufgabe ist das Füllen der Listenfelder auf Basis der mit dem Öffnungsargument übergebenen Informationen. Diese Aufgabe übernimmt die Prozedur, die beim Laden des Formulars ausgelöst wird. Bevor wir uns diese ansehen, noch ein Hinweis zum Zugriff auf die beiden Listenfelder mit den Daten der abzugleichenden Datensätze: Da zwischen den beiden Listenfeldern und auch zwischen Hauptformular und Listenfeldern eine Menge Kommunikation nötig ist, haben wir der Einfachheit halber zwei Objektvariablen in das Klassenmodul des Hauptformulars gelegt, welche die beiden Listenfelder referenzieren. Die notwendigen Objektvariablen werden so deklariert:

Dim WithEvents lstZieltabelle As Listbox
Dim WithEvents lstQuelltabelle As Listbox

Das Schlüsselwort WithEvents sorgt dafür, dass wir auch die Ereignisprozeduren der mit diesen Variablen referenzierten Steuerelemente im Klassenmodul des Hauptformulars behandeln können.

Die Prozedur Form_Load aus Listing 2 deklariert zunächst eine Variablen. Danach weist sie den beiden Objektvariablen lstZieltabelle und lstQuelltabelle die entsprechenden Steuerelemente des Unterformulars zu. Außerdem legt sie fest, dass das Ereignis Nach Aktualisierung dieser beiden Steuerelemente im aktuellen Klassenmodul berücksichtigt werden soll. Zu den betroffenen Ereignisprozeduren kommen wir weiter unten.

Listing 2: Anzeigen der abzugleichenden Daten im Formular frmAbgleichDetails

Private Sub Form_Load()
    Dim db As DAO.Database
    Dim rstQuelle As DAO.Recordset, rstZiel As DAO.Recordset
    Dim strQuelltabelle As String, strZieltabelle As String
    Dim strPKQuelle As String, strPKZiel As String
    Dim varIDQuelle As Variant, varIDZiel As Variant
    Dim strOpenArgs As String
    Dim strFelder As String
    Dim strWerteQuelle As String, strWerteZiel As String
    Dim i As Integer
    Set db = CurrentDb
    Set lstZieltabelle = Me!sfm.Form!lstZieltabelle
    lstZieltabelle.AfterUpdate = "[Event Procedure]"
    Set lstQuelltabelle = Me!sfm.Form!lstQuelltabelle
    lstQuelltabelle.AfterUpdate = "[Event Procedure]"
    strOpenArgs = Me.OpenArgs
    strPKZiel = Split(strOpenArgs, "|")(0)
    strPKQuelle = Split(strOpenArgs, "|")(1)
    varIDZiel = Split(strOpenArgs, "|")(2)
    varIDQuelle = Split(strOpenArgs, "|")(3)
    strZieltabelle = Split(strOpenArgs, "|")(4)
    strQuelltabelle = Split(strOpenArgs, "|")(5)
    strFelder = Split(strOpenArgs, "|")(6)
    Set rstQuelle = db.OpenRecordset("SELECT " & Replace(strFelder, ";", ",") & " FROM " _
    & strQuelltabelle & " WHERE " & strPKQuelle & " = " & varIDQuelle, dbOpenDynaset)
    Set rstZiel = db.OpenRecordset("SELECT " & Replace(strFelder, ";", ",") & " FROM " _
    & strZieltabelle & " WHERE " & strPKZiel & " = " & varIDZiel, dbOpenDynaset)
    For i = LBound(Split(strFelder, ";")) To UBound(Split(strFelder, ";"))
        strWerteQuelle = strWerteQuelle & ";" & rstQuelle(Split(strFelder, ";")(i))
        strWerteZiel = strWerteZiel & ";" & rstZiel(Split(strFelder, ";")(i))
    Next i
    Me!sfm.Form!lstFelder.RowSource = ";" & strFelder
    strWerteQuelle = "[Alle auswählen]" & strWerteQuelle
    strWerteZiel = "[Alle auswählen]" & strWerteZiel
    lstQuelltabelle.RowSource = strWerteQuelle
    lstZieltabelle.RowSource = strWerteZiel
    bolZielAlle = True
    bolQuelleAlle = False
    For i = 0 To lstZieltabelle.ListCount
        lstZieltabelle.Selected(i) = True
    Next i
End Sub

Danach werden die einzelnen Bestandteile des Öffnungsarguments in verschiedene Variablen eingelesen. Der Zugriff auf die durch das Pipe-Zeichen getrennten Werte erfolgt über die Split-Funktion, die ein Array der durch das angegebene Zeichen getrennten Zeichenketten erzeugt. Durch Angabe des Indexes erhalten Sie Zugriff auf das entsprechende Element des Arrays.

Mit diesen Informationen erzeugt die Prozedur zwei Datensatzgruppen, die jeweils einen Datensatz enthalten: den Quell- und den Zieldatensatz.

Ende des frei verfügbaren Teil. Wenn Du mehr lesen möchtest, hole Dir ...

den kompletten Artikel im PDF-Format mit Beispieldatenbank

diesen und alle anderen Artikel mit dem Jahresabo

Schreibe einen Kommentar