Zur Hauptseite ... Zum Onlinearchiv ... Zum Abonnement ... Zum Newsletter ... Zu den Tools ... Zum Impressum ... Zum Login ...

Achtung: Dies ist nicht der vollständige Artikel, sondern nur ein paar Seiten davon. Wenn Sie hier nicht erfahren, was Sie wissen möchten, finden Sie am Ende Informationen darüber, wie Sie den ganzen Artikel lesen können.

Kompletten Artikel lesen?

Einfach für den Newsletter anmelden, dann lesen Sie schon in einer Minute den kompletten Artikel und erhalten die Beispieldatenbanken.

E-Mail:

Gedrucktes Heft

Diesen Beitrag finden Sie in Ausgabe 1/2004.

Unser Angebot für Sie!

Lesen Sie diesen Beitrag und 500 andere sofort im Onlinearchiv, und erhalten Sie alle zwei Monate brandheißes Access-Know-how auf 72 gedruckten Seiten! Plus attraktive Präsente, zum Beispiel das bald erscheinende Buch 'Access 2010 - Das Grundlagenbuch für Entwickler'!

Diesen Beitrag twittern

Änderungshistorie von Daten

André Minhorst, Duisburg, und Dr. Holger H. Stutzke, Bremen

Viele Anwendungen verlangen eine konsistente Historie aller Änderungen im Datenbestand. Access bietet dazu keine perfekten Möglichkeiten, aber mit ein wenig Eigeninitiative seitens des Entwicklers ist die lückenlose Historie dennoch leicht realisierbar. Je nachdem, ob die Historie wirklich lückenlos sein muss oder ob Informationen wie Anlege-, Änderungs- und Löschdaten der einzelnen Datensätze ausreichen, gibt es zwei Varianten für die Pflege einer Historie.

Grundlagen

Bei diversen Anwendungsfällen wird eine konsistente Speicherung aller Daten und Datenänderungen in einer Datenbank erwartet.

Dabei kann es sich um sicherheits- oder finanztechnisch relevante Anwendungen handeln, bei denen eine lückenlose Historie sogar Pflicht ist, oder man möchte aus anderen Gründen genau wissen, zu welchem Zeitpunkt welcher Datenbestand Gültigkeit hatte. Wieder andere Anwendungen erfordern nur rudimentäre Informationen über die Änderung von Daten wie das jeweilige Datum und den durchführenden Benutzer beim Erstellen, letzten Ändern oder Löschen eines Datensatzes.

Beide Methoden erfordern, dass die gewünschten Daten beim Erstellen, Ändern oder Löschen von Informationen gespeichert werden, und das natürlich automatisch.

Access bietet dazu keine speziellen Mittel, sodass die benötigten Aktionen unmittelbar bei der Dateneingabe, also im entsprechenden Formular, vorgenommen werden müssen. Da die Speicherung automatisch erfolgen soll, verwendet man am besten die Ereignisprozeduren, die unmittelbar vor beziehungsweise nach der Änderung der Daten ausgelöst werden.

Client-Server-Systeme wie Microsoft SQL Server, dessen abgespeckte Version MSDE und andere bieten für solche Änderungsdaten so genannte Trigger an, die automatisch beim Anlegen, Ändern oder Löschen von Datensätzen ausgelöst werden und die Werte der Tabellenfelder vor und nach der Änderung bereitstellen.

Da Access diese Vorzüge nicht bietet, lernen Sie im vorliegenden Beitrag, wie Sie eine formulargesteuerte Funktionalität zur Pflege einer Änderungshistorie erstellen.

Die Besonderheit der
Protokollierung von
Löschvorgängen

Sie können natürlich nur eine Änderungshistorie zu Datensätzen führen, die auch vorhanden sind. Sie müssen sich also an dieser Stelle entscheiden, ob mit einem gelöschten Datensatz auch die Historie des Datensatzes gelöscht werden soll. Lautet die Antwort ja, haben Sie sich definitiv für die einfacher zu realisierende Variante entschieden.

Leider sehen die Anforderungen sicherheits- oder finanztechnisch kritischer Anwendungen den anderen Fall vor. Das bedeutet, dass Sie auch gelöschte Datensätze nicht so einfach entfernen dürfen. Und damit stellt sich erneut eine wichtige Frage: Möchten Sie die gelöschten Daten mit einem entsprechenden Flag versehen und alle Abfragen und Datenherkünfte so anpassen, dass nur als nicht gelöscht gekennzeichnete Datensätze angezeigt werden, oder möchten Sie die Datensätze tatsächlich aus der Ursprungstabelle löschen, im gleichen Schritt aber in einer weiteren Tabelle gleichen Aufbaus archivieren?

Die Auflistung der Techniken und der Vor- und Nachteile der beiden Varianten könnte wahrscheinlich einen eigenen Beitrag füllen. An dieser Stelle wird davon ausgegangen, dass Performance und Speicherplatz Sie nicht daran hindern, gelöschte Daten durch das Setzen eines Flags als solche zu markieren und sie nicht zu löschen oder zu verschieben.

Ermitteln des Benutzers

Wenn Änderungen unter Angabe des Ausführenden gespeichert werden sollen, müssen Sie dessen Identität ermitteln. Das können Sie auf unterschiedliche Arten erledigen. Die richtige Auswahl hängt unter anderem davon ab, ob die Datenbank das Sicherheitssystem von Access verwendet. Falls ja, können Sie einfach den Namen des aktuellen Benutzers eintragen. Den Namen können Sie mit folgender Funktion ermitteln:

=CurrentUser()

Falls nein, können Sie beispielsweise den Namen des aktuell auf dem Rechner eingeloggten Benutzers verwenden - Beispiele für die Ermittlung dieses Benutzers finden Sie im Modul mdlBenutzerinformationen der Beispieldatenbank.

Einfache Änderungshistorie

Die einfache Änderungshistorie dient einfach nur der Protokollierung des Benutzers und des Datums für das Anlegen, die letzte Änderung und für das Löschen eines Datensatzes. Sie erfordert folgende Maßnahmen:

  • Hinzufügen von Feldern zum Speichern der Änderungsdaten in den entsprechenden Tabellen
  • Hinzufügen von Ereignisprozeduren zu den Formularen, in denen die Daten bearbeitet werden
  • Hinweis

    Die Beschreibung der Maßnahmen erfolgt anhand der Tabellen Artikel, Kategorie und Lieferanten sowie des Formulars Artikel, die Sie zum Nachvollziehen der nachfolgenden Schritte am besten aus der Nordwind-Datenbank in eine neue, leere Datenbank importieren. Sie finden die fertigen Beispiele allerdings auch auf der Heft-CD. Die Dateien heißen Historie97.mdb (für Access 97) und Historie00.mdb (für Access 2000 und höher). (

    Vorbereiten der Tabelle

    Damit Sie die Änderungsdaten in der Tabelle speichern können, müssen Sie den Entwurf entsprechend anpassen. Dazu legen Sie die folgenden Felder neu an:

  • ErstelltAm
  • ErstelltDurch
  • LetzteAenderungAm
  • LetzteAenderungDurch
  • GeloeschtAm
  • GeloeschtDurch
  • Die Felder zum Speichern der Datumsangaben erhalten den Datentyp Datum/Zeit, die Felder zum Speichern der jeweiligen Benutzer den Datentyp Text.
  • Anpassen des Formulars

    Nun passen Sie das Formular so an, dass bei jeder Änderung an einem Datensatz eine entsprechende Protokollierung erfolgt.

    Das bedeutet, dass Sie drei unterschiedliche Aktionen berücksichtigen müssen: das Anlegen neuer Datensätze und das Ändern und Löschen bestehender Datensätze.

    Private Sub Form_BeforeInsert(Cancel As Integer)

        Me!AngelegtAm = Date

        Me!AngelegtDurch = CurrentUser

    End Sub

    Quellcode 1

    Private Sub Form_BeforeUpdate(Cancel As Integer)

        Me!GeaendertAm = Date

        Me!GeaendertDurch = CurrentUser

    End Sub

    Quellcode 2

    Private Sub Form_BeforeUpdate(Cancel As Integer)

        If Me.NewRecord Then

            Me!AngelegtAm = Date

            Me!AngelegtDurch = CurrentUser

        Else

            Me!GeaendertAm = Date

            Me!GeaendertDurch = CurrentUser

        End If

    End Sub

    Quellcode 3

    Hinweis

    Die nachfolgende Beschreibung bezieht sich auf das Formular Artikel der Nordwinddatenbank. (

    Anlegen von Datensätzen

    Das Anlegen eines Datensatzes löst das Ereignis Vor Eingabe aus. Das Speichern dieses neuen Datensatzes löst das Ereignis Nach Eingabe aus. Das erstgenannte Ereignis ist für das Anlegen der Änderungsdaten interessant. Legen Sie für diese Ereigniseigenschaft die Prozedur aus Quellcode 1 an.

    Wenn Sie nun einen neuen Datensatz anlegen, weist die Prozedur den beiden Feldern AngelegtAm und AngelegtDurch die Werte der Funktionen Date und CurrentUser zu.

    Ändern von Datensätzen

    Eine Datensatzänderung liegt immer vor, wenn mindestens ein Feld des Datensatzes geändert wurde. Das Ereignis, das beim Speichern eines geänderten Datensatzes ausgelöst wird, heißt Vor Aktualisierung. Unmittelbar nach dem Speichern wird noch das Ereignis Nach Aktualisierung ausgelöst - soweit der Speichervorgang nicht in der Ereignisprozedur für das Ereignis Vor Aktualisierung abgebrochen wird oder ein Fehler auftritt. Mit der Ereignisprozedur aus Quellcode 2 legen Sie die Änderungsdaten an.

    Die Prozedur belegt die beiden Felder GeaendertAm und GeaendertDurch mit den entsprechenden Werten. Direkt im Anschluss wird die neue Version des Datensatzes gespeichert.

    Anlegen und Ändern in einem Schritt?

    Zu beachten ist, dass auch das Neuanlegen eines Datensatzes diese beiden Prozeduren auslöst. Damit würden beim Neuanlegen sowohl die Felder für das Neuanlegen als auch für das Ändern eines Datensatzes aktualisiert.

    Wenn die Felder GeaendertAm und GeaendertDurch beim Neuanlegen eines Datensatzes nicht geändert werden sollen, verwenden Sie die Prozedur aus Quellcode 3 für das Ereignis Vor Aktualisierung.

    Die Prozedur überprüft, ob es sich bei dem Datensatz um einen neuen Datensatz handelt, und ändert die entsprechenden Felder.

    Löschen von
    Datensätzen

    Das Löschen eines Datensatzes löst das Ereignis Beim Löschen aus. Da das Löschen eines Datensatzes auch automatisch die Historie mitlöschen würde, sollen lediglich die beiden Felder GeloeschtDurch und GeloeschtAm aktualisiert und der eigentliche Löschvorgang abgebrochen werden.

    Zusätzlich müssen Sie natürlich die Datenherkunft des Formulars so anpassen, dass Datensätze, die einen Wert für eines der Felder GeloeschtAm oder GeloeschtDurch enthalten, nicht mehr angezeigt werden. Daher ändern Sie die Eigenschaft Datenherkunft auf den folgenden Wert:

    Private Sub Form_Delete(Cancel As Integer)

        Geloescht = True

    End Sub

    Private Sub Form_BeforeDelConfirm(Cancel As Integer, Response As Integer)

        Cancel = True

    End Sub

    Private Sub Form_AfterDelConfirm(Status As Integer)

        Me!GeloeschtAm = Date

        Me!GeloeschtDurch = CurrentUser

        Me.Requery

    End Sub

    Quellcode 4

    Private Sub Form_BeforeUpdate(Cancel As Integer)

        If Geloescht = True Then

            Geloescht = False

        Else

            If Me.NewRecord Then

                Me!AngelegtAm = Date

                Me!AngelegtDurch = CurrentUser

            Else

                Me!GeaendertAm = Date

                Me!GeaendertDurch = CurrentUser

            End If

        End If

    End Sub

    Quellcode 5

    SELECT * FROM Artikel WHERE GeloeschtAm IS NULL

    Der benötigte Vorgang ist ein wenig komplizierter und Sie brauchen dazu drei Funktionen: Beim Löschen, Vor Löschabfrage und Nach Löschabfrage. Der Eigenschaft Beim Löschen können Sie eine Prozedur hinzufügen, die den Löschvorgang unter bestimmten Umständen abbricht und weitere Anweisungen ausführt.

    Das wäre für diesen Zweck eigentlich ausreichend, denn hier könnten Sie die Werte der beiden Felder GeloeschtAm und GeloeschtDurch auf die entsprechenden Werte einstellen.

    Leider können Sie in dieser Prozedur nicht die Requery-Methode des Formulars aufrufen, die unter anderem dem Aktualisieren der Datenherkunft des Formulars dient. Das würde bedeuten, dass zwar die beiden Felder GeloeschtAm und GeloeschtDurch die gewünschten Werte haben, aber dass weder der Datensatz noch die Datenherkunft des Formulars aktualisiert sind - was schlichtweg gleichbedeutend damit ist, dass der Benutzer den Datensatz noch sehen kann.

    Abb. 1: Entwurfsansicht der Tabelle tblAenderungen

    Damit der Datensatz als gelöscht markiert und direkt anschließend die Datenherkunft aktualisiert wird, verwenden Sie die drei Prozeduren aus Quellcode 4 für die drei oben genannten Ereigniseigenschaften.

    Zusätzlich deklarieren Sie im Kopf des Klassenmoduls noch eine Variable:

    Dim Geloescht As Boolean

    In der Prozedur Form_Delete wird nur die Variable Geloescht auf den Wert True gesetzt. Damit wird der Löschvorgang an dieser Stelle noch nicht abgebrochen, sondern zunächst durchgeführt! Erst in der Prozedur Form_BeforeDelConfirm wird der Parameter Cancel auf den Wert True gesetzt und der Löschvorgang damit rückgängig gemacht.

    Die Prozedur Form_AfterDelConfirm schließlich setzt die beiden Felder GeloeschtAm und GeloeschtDurch auf die entsprechenden Werte und aktualisiert die Datenherkunft. Da diese nur die Datensätze enthält, deren Feld GeloeschtAm Null ist, wird der soeben ‚gelöschte’ Datensatz nicht mehr angezeigt.

    Durch die Requery-Methode des Formulars wird unter anderem das Ereignis Vor Aktualisierung ausgelöst, das ja, wie oben beschrieben, die beiden Felder GeaendertAm und GeaendertDurch aktualisiert. Beim Löschen eines Datensatzes sollen diese beiden Werte allerdings nicht angepasst werden. Daher ändern Sie die entsprechende Ereignisprozedur wie in Quellcode 5.

    Die Funktion hat nun eine zusätzliche If-Abfrage, die den Wert der Variablen Geloescht überprüft. Hat dieser den Wert True, wird die Anpassung der Felder GeaendertAm und GeaendertDurch nicht durchgeführt. Die Variable Geloescht wird wieder auf den Wert False gesetzt, damit bei einer eventuell folgenden Änderung die Änderungsinformationen wieder gesetzt werden können.

    Ausführliche Änderungshistorie

    Wenn die Ansprüche an die Konsistenz der Historie höher sind und der Zustand der Datenbank zu jedem Zeitpunkt rekonstruierbar sein soll, ist ein wenig mehr Aufwand erforderlich.

    Die Änderungshistorie soll sämtliche Änderungen speichern - vom Erstellen des Datensatzes über die Änderung einzelner Felder bis hin zum Löschen des Datensatzes.

    Alle Änderungen werden in einer separaten Tabelle archiviert. Diese Tabelle enthält Felder zum Speichern des Tabellennamens und Feldnamens, in dem die Änderung vorgenommen wurde, den Zeitpunkt der Änderung sowie den alten und den neuen Wert und den Benutzer, in dessen Kontext die Änderungen durchgeführt werden.

    Außerdem speichert die Tabelle die Aktion, die mit der jeweiligen Änderung zusammenhängt - also anlegen, ändern oder löschen. Sehr wichtig ist die Angabe des Wertes des Primärschlüsselfeldes des geänderten Datensatzes. Den Entwurf dieser Tabelle finden Sie in Abb. 1.

    Private Sub Form_BeforeUpdate(Cancel As Integer)

        Dim Primaerschluesselfeld As String

        Dim db As DAO.Database

        Dim rst As DAO.Recordset

        Dim ctl As Control

        Dim ctlType As Integer

        Dim ctlSource As String

        Dim rstSource As String

        Dim AlterWert As String

        Dim NeuerWert As String

        Dim Aktion As String

        If Me.NewRecord Then

            Aktion = "Neuanlage"

        Else

            Aktion = "Änderung"

        End If

        Primaerschluesselfeld = "Lieferanten-Nr"

        rstSource = Me.RecordSource

        Set db = CurrentDb

        Set rst = db.OpenRecordset("tblAenderungen", dbOpenDynaset)

    Quellcode 6 (erster Teil)

    Voraussetzungen

    Die Änderungshistorie erfolgt formulargesteuert, das bedeutet, dass lediglich die in einem Formular vorgenommenen Änderungen auch archiviert werden.

    Änderungen, die Sie direkt an den Tabellen vornehmen, werden nicht berücksichtigt. Dadurch, dass die Änderungen durch Formularereignisse gespeichert werden, sind einige Voraussetzungen zu erfüllen:

  • Die Datenherkunft muss eine Tabelle sein, es darf keine Abfrage verwendet werden.
  • Die Datenherkunft muss einen eindeutigen Primärindex haben, der nicht aus mehr als einem Feld bestehen darf und im Entwurf an erster Stelle stehen muss.
  • Sie haben das Ende des frei verfügbaren Teils des Artikels erreicht. Lesen Sie weiter, um zu erfahren, wie Sie den vollständigen Artikel lesen und auf viele hundert weitere Artikel zugreifen können.

    Sind Sie Abonnent?Jetzt einloggen ...
     

    Kompletten Artikel lesen?

    Einfach für den Newsletter anmelden, dann lesen Sie schon in einer Minute den kompletten Artikel und erhalten die Beispieldatenbanken.

    E-Mail:

    © 2003-2015 André Minhorst Alle Rechte vorbehalten.