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 4/2009.

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

Zusammenfassung

Erweitern Sie Ihre Datenbank ohne viel Aufwand um die Pflege von Änderungsinformationen.

Techniken

Formulare, VBA, Datenmodellierung

Voraussetzungen

Access 2000 und höher

Beispieldateien

AenderungsdatenProtokollieren.mdb

Shortlink

672

Änderungsdaten protokollieren

André Minhorst, Duisburg

Wenn mehrere Benutzer mit den Daten einer Datenbank arbeiten, möchten Sie für die relevanten Tabellen vielleicht nachhalten, wer wann welchen Datensatz angelegt, bearbeitet oder gelöscht hat. Dazu sind zwei Schritte nötig: Das Hinzufügen der Felder zum Speichern dieser Informationen in den relevanten Tabellen und das Eintragen dieser Informationen, wenn es soweit ist. Dieser Beitrag zeigt, wie Sie mit minimalem Aufwand ein solches Protokoll einrichten.

Eine detaillierte Historie der Änderungen an Daten samt Archivierung der Daten vor jeder Änderung ist aufwendig und wird nur selten benötigt. Häufiger trifft man den Fall an, dass man einfach nur wissen möchte, wer zum Beispiel einen Kunden angeleg oder wer eine Bestellung zuletzt geändert oder gelöscht hat.

Beim Anlegen und Bearbeiten der Daten ist dies gar kein Problem: Sie fügen der Tabelle einfach je zwei Felder zum Speichern des Datums der Aktion und des Mitarbeiters hinzu und sehen an den entsprechenden Stellen, also beispielsweise in den Formularen zur Bearbeitung dieser Daten, die benötigten Codezeilen zum Eintragen der Änderungsdaten vor.

Beim Löschen wird dies schon schwieriger: Wo wollen Sie ein Löschdatum und einen Verweis auf den Verantwortlichen unterbringen, wenn der Datensatz anschließend nicht mehr vorhanden ist? Ganz einfach: Sie löschen den Datensatz gar nicht, sondern versehen ihn mit einem Marker.

So können Sie auch das Löschdatum und den löschenden Mitarbeiter ganz einfach hinzufügen. Dass der Datensatz ja nun gar nicht physisch gelöscht ist, ist zwar kein Problem, bringt aber ein wenig zusätzlichen Aufwand mit sich: Alle Abfragen, Formulare, Berichte, Steuerelemente und Codeabschnitte, die sich auf die Daten der Tabelle mit den vermeintlich gelöschten Datensätzen beziehen, müssen um eine entsprechende WHERE-Klausel ergänzt werden, die alle Datensätze ausschließt, für die der Wert eines Feldes etwa mit dem Namen GeloeschtAm nicht Null ist.

Im Gegenzug können Sie aber auch später noch auf die Daten zugreifen, die bereits gelöscht wurden - beispielsweise, um diese entgültig zu löschen, zu archivieren oder um Auswertungen auf den gesamten Datenbestand zu fahren.

Tabellen anpassen

Wie üblich möchten wir den Aufwand zum Einbau dieser Lösung möglichst gering halten. Das betrifft zum Beispiel das Hinzufügen der Felder mit den Änderungsdaten zu den betroffenen Tabellen.

Normalerweise öffnet man jede dieser Tabellen im Entwurf, fügt die gewünschten Felder hinzu, verknüpft diese gegebenenfalls mit einer Mitarbeitertabelle, um sich per Fremdschlüssel auf die ausführenden Mitarbeiter beziehen zu können, und speichert dann die Tabelle.

Und das erledigt man nicht nur für eine, sondern für alle Tabellen, deren Änderungsdaten protokolliert werden sollen.

Puh, das ist aber langweilig - da setzen wir uns doch lieber mal ein paar Minuten hin und programmieren eine kleine Funktion, die uns diese Aufgabe abnimmt.

Voraussetzung für die nachfolgend beschriebene Prozedur ist eine Benutzertabelle und die Anmeldung der Benutzer beim Start der Datenbank. Für Beispielzwecke soll diese möglichst einfach aussehen - zum Beispiel wie in Abb. 1.

pic001.png

Abb. 1: Diese Tabelle soll in den Feldern zum Eintragen der Änderungen per Fremdschlüssel referenziert werden.

Die Änderungsfelder legen wir mit einigen SQL-Anweisungen an, die wir mit der Execute-Methode des Database-Objekts ausführen. Werfen wir zunächst einen Blick auf die nackten SQL-Anweisungen. Die erste soll einfach nur ein Datumsfeld namens AngelegtAm hinzufügen und sieht so aus:

ALTER TABLE tblKunden

ADD AngelegtAm DATETIME

Sie können diese Anweisung ausprobieren, indem Sie eine neue, leere Abfrage im Entwurf öffnen und dann zur SQL-Ansicht wechseln. Dort tragen Sie den SQL-Ausdruck ein und führen ihn aus.

Wir brauchen noch zwei weitere Anweisungen, von denen die erste das Feld zum Speichern des durchführenden Benutzers anlegt und das zweite die Beziehung von diesem Fremdschlüsselfeld zur Tabelle tblBenutzer:

ALTER TABLE tblKunden ADD AngelegtDurch INTEGER

ALTER TABLE tblKunden ADD CONSTRAINT

FKAngelegtDurch FOREIGN KEY (AngelegtDurch)

REFERENCES tblKunden

Zusammengefasst in einer Funktion sehen die SQL-Anweisungen wie in Listing 1 aus. Der Aufruf für unsere Beispielkonstellation mit einer Tabelle tblBenutzer für die Benutzerdaten und mit einer Tabelle tblKunden, die die Felder zum Eintragen der Änderungsdaten erhalten soll, sieht so aus:

Listing 1: Hinzufügen von History-Feldern zu einer Tabelle

Public Function AddHistoryFieldsToTable(strTableChange As String, strTableUsers As String)

    'AngelegtAm und AngelegtDurch

    dbs.Execute "ALTER TABLE " & strTableChange & " ADD AngelegtAm DATETIME", dbFailOnError

    dbs.Execute "ALTER TABLE " & strTableChange & " ADD AngelegtDurch INTEGER", dbFailOnError

    dbs.Execute "ALTER TABLE " & strTableChange & " ADD CONSTRAINT FKAngelegtDurch " _

    & "FOREIGN KEY (AngelegtDurch) REFERENCES " & strTableUsers, dbFailOnError

    'ZuletztGeaendertAm und ZuletztGeaendertDurch

    dbs.Execute "ALTER TABLE " & strTableChange & " ADD ZuletztGeaendertAm DATETIME", dbFailOnError

    dbs.Execute "ALTER TABLE " & strTableChange & " ADD ZuletztGeaendertDurch INTEGER", dbFailOnError

    dbs.Execute "ALTER TABLE " & strTableChange & " ADD CONSTRAINT FKGeaendertDurch " _

    & "FOREIGN KEY (GeaendertDurch) REFERENCES " & strTableUsers, dbFailOnError

    'GeloeschtAm und GeloeschtDurch

    dbs.Execute "ALTER TABLE " & strTableChange & " ADD GeloeschtAm DATETIME", dbFailOnError

    dbs.Execute "ALTER TABLE " & strTableChange & " ADD GeloeschtDurch INTEGER", dbFailOnError

    dbs.Execute "ALTER TABLE " & strTableChange & " ADD CONSTRAINT FKGeloeschtDurch " _

    & "FOREIGN KEY (GeloeschtDurch) REFERENCES " & strTableUsers, dbFailOnError

End Function

AddHistoryFieldsToTable "tblKunden", "tblBenutzer"

Verwenden Sie diesen Aufruf für alle Tabellen, für deren Datensätze Sie Änderungsinformationen speichern möchten. Das Ergebnis sieht wie in Abb. 2 aus. Was Sie hier nicht erkennen können, sind die Beziehungen, welche die Funktion aus Listing 1 zwischen den Fremdschlüsselfeldern AngelegtDurch, ZuletztGeaendertAm und GeloeschtAm und der Tabelle tblBenutzer anlegt. Abb. 3 liefert den Beweis, dass auch die Beziehungen ordnungsgemäß angelegt wurden.

pic002.png

Abb. 2: Eine Beispieltabelle mit Feldern zum Speichern von Änderungsinformationen

pic003.png

Abb. 3: Diese Beziehungen wurden mit der Funktion aus Listing 1 angelegt.

Alternative Tabellenanpassung

Es gibt noch eine Alternative zur beschriebenen Vorgehensweise: Dabei würden Sie die sechs Felder zum Festhalten der Änderungsinformationen nicht direkt in die Tabellen schreiben, sondern in eine separate Tabelle. Diese enthält neben den sechs Feldern noch zwei weitere Felder zum Speichern der Tabelle und des Datensatzes, auf die sich die Informationen beziehen.

Der Nachteil dieser Vorgehensweise ist, dass der Aufwand für das Herausfiltern von als gelöscht markierten Daten relativ hoch ist. Daher sehen wir an dieser Stelle von einer ausführlicheren Beschreibung dieser Variante ab.

Änderungsdaten pflegen

Der nächste Schritt ist etwas aufwendiger: Sie müssen prüfen, an welchen Stellen der Datenbank Operationen auf Basis der Daten dieser Tabelle durchgeführt werden. Überall dort müssen Sie per Code oder über entsprechende Änderungen an eventuell vorhandenen Aktionsabfragen dafür sorgen, dass bei Änderungen auch die nötigen Informationen in die soeben angelegten Felder eingetragen werden.

Leichter haben Sie es, wenn Sie die Anwendung ohnehin gerade erst erstellen - Sie laufen dann weniger Gefahr, die Stellen, an denen die Daten geändert werden, zu übersehen.

Vielleicht ist das Ganze aber auch gar nicht so aufwendig. Gehen wir einmal von der Annahme aus, dass Sie Daten nur über Formulare, über die Execute-Methode des Database-Objekts oder per DAO mit AddNew, Edit und Update ändern. Dann ergeben sich möglicherweise verallgemeinernde Vereinfachungen - aber schauen Sie doch selbst.

Änderungsdaten in Formularen

In Formularen gibt es zwei Ereignisse, die beim Speichern eines neuen oder geänderten beziehungsweise beim Löschen eines Datensatzes ausgelöst werden. Das Ereignis Vor Aktualisierung beispielsweise feuert immer beim Speichern eines geänderten Datensatzes, egal, ob es sich um einen neuen oder einen vorhandenen Datensatz handelt.

Zu Beispielzwecken legen Sie nun ein einfaches Formular an, das alle Felder der oben beschriebenen Tabelle tblKunden enthält. Erstellen Sie dann eine Prozedur für die Ereigniseigenschaft Vor Aktualisierung, die wie folgt aussieht:

Private Sub Form_BeforeUpdate(Cancel As Integer)

    If Me.NewRecord = True Then

        Me!AngelegtAm = Now

    Else

        Me!ZuletztGeaendertAm = Now

    End If

    End Sub

Die Prozedur prüft, ob gerade ein neu angelegter (Me.NewRecord = True) oder ein bestehender Datensatz geändert wurde und nun gespeichert werden soll. Im Falle eines neuen Datensatzes schreibt die Routine noch das aktuelle Datum samt Zeit in das Feld AngelegtAm, bei einem vorhandenen Datensatz ist das Feld ZuletztGeaendertAm das Ziel. Das ist alles - Änderungen im Formular werden so zuverlässig protokolliert.

Betrachten wir nun das Löschen eines Datensatzes. Das Löschen löst das Ereignis Beim Löschen aus, wofür Sie die folgende Routine hinterlegen:

Private Sub Form_Delete(Cancel As Integer)

    Me!GeloeschtAm = Now

    Me.Dirty = False

    Cancel = True

    End Sub

Die Routine stellt das Löschdatum des Datensatzes auf das aktuelle Datum samt Zeit ein, speichert den Datensatz (Me.Dirty = True) und bricht den Löschvorgang ab, damit der Datensatz nicht wirklich gelöscht wird (sonst hätten wir wohl nichts vom frisch geänderten Löschdatum ...).

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:

Verwandte Beiträge:

Benutzerverwaltung

Formularposition speichern und wiederherstellen

Ereignisprozeduren

Modale Dialoge mal anders

Ereignisse im Eigenbau

Access, MySQL und Berechtigungsverwaltung

Validieren mit Klasse

Transparenz und andere Effekte in Formularen

Formulare für die Dateneingabe

Verknüpfte Datenbanken updaten

Ereignisprozeduren implantieren

Professionelle Datenmodellierung mit Access

Indizierung mit Access

Unterformulare: Daten anlegen und löschen

Alphabetisches Register

Beschreibung von Tabellen und Co. nutzen

Tipps und Tricks

Hierarchien visualisieren

Fortschrittsanzeige

Datenbank nach Vorlage

Lookup-Daten verwalten

Kein Datensatz- und Positionswechsel bei Requery

Meldungsfenster im Eigenbau

Projektzeitmanager

Zeugnisverwaltung mit Access

Zoomfenster im Eigenbau

© 2003-2015 André Minhorst Alle Rechte vorbehalten.