15.1 Zeitlich fixiert oder zeitabhängig

In jeder Datenbank gibt es Daten, die von vorneherein zeitlich fixiert sind. Dies bedeutet, zum zugehörigen Datensatz (zum Tupel) gehört ein Attribut, das einen Zeitpunkt festhält. Zum Beispiel ...

Zeitlich fixiert

  • Bei einer Rechnung der Rechnungskopf mit seinem Datum
  • Bei einer Gewichtsmessung die Angabe des Messzeitpunktes
  • Beim Auftragseingang das Datum

Solche Einträge in die Datenbank behalten diese zeitliche Fixierung bis zum Ende der Datenbank und brauchen im weiteren nicht betrachtet werden. Wird diese Information vielleicht später wieder benötigt, ist sie da.

Die meisten Informationen haben aber diese zeitliche Fixierung nicht, sondern erfassen nur den aktuellen Informationsstand zum Zeitpunkt der Datenerfassung. Bei jedem erneuten Eintrag werden die früheren Daten überschrieben. Zum Beispiel bei einer Relation zu Artikeln in einem WebShop.

Nur der aktuelle Stand

Artikel (#ArtNr, Beschr, Preis)

Ändert sich dort z.B. der Preis eines Artikels, wird der alte überschrieben und steht (in der Datenbank) nicht mehr zur Verfügung. Genauso die Beschreibung, usw. Oder nehmen wir eine Kundenrelation:

Kunden (#KuNr, Name, VName, PLZ, ORT, Straße, Tel)

Hier können sich im Zeitablauf die Adressangaben ändern, auch die Telefonnummer und evtl. sogar der Name. Wenn einfach überschrieben wird, sind die alten Daten weg. Dies sind also zeitabhängige Daten. Bei ihnen muss geprüft werden, ob das "Verschwinden durch Überschreiben" akzeptiert werden kann. Oft kann man es deshalb nicht, weil der alte Zustand zum Zeitpunkt der Entstehung der Daten erhalten bleiben muss, z.B. aus steuerlichen Gründen. Dies kann Rechnungen, aber auch andere Geschäftsobjekte betreffen.

Zeitabhängige Daten

Früher wurden dafür Belege abgelegt und füllten ganze Archive, später und auch heute noch Faksimiles in DVD-Stapeln archiviert oder Datenbestände dupliziert. Andere Lösungen wurden für NoSQL-Datenbanken gefunden. Hier nun eine Lösung, die mit Hilfe der relationalen Datenbanktechnologie eine Sicherung über die Zeit ermöglicht.

15.2 Duplizieren zum Zeitpunkt der Rechnungsstellung

Sie besteht darin, die zeitabhängigen Daten zum Entstehungszeitpunkt zu duplizieren und ebenfalls in der Datenbank zu speichern. Dazu werden die duplizierten Daten der Relation zugeordnet, von deren Schlüssel sie funktional abhängig sind.

Beispiel Rechnungsstellung

Diese Vorgehensweise wird an einer einfachen Fassung eines Datenmodells zur Rechnungsstellung demonstriert. Gegeben seien die folgenden Relationen:

Adressen (#AdrNr, PLZ, Ort, Straße, Telefon)

Artikel (#ArtNr, Beschr, Preis)

KuAdr (#(KNr, AdressNr)) //Kundenadressen

Kunden (#KNr, Name, Vorname)

ReKöpfe (#ReNr, Datum, Verkäufer, KVDAT) //Rechnungsköpfe

RePos (#(ReNr, PosNr), ArtikelNr, Anzahl) //Rechnungspositionen

KVDAT bedeutet Kaufvertragsdatum, ein Kunde kann beliebig viele Adressen haben, unter einer Adresse können mehrere Kunden wohnen. Eine größere Fassung dieses Datenmodells findet sich in Abschnitt 16.1.

Nun zum Duplizieren der Daten. Als erstes müssen die Daten bestimmt werden, die zeitabhängig sind und die evtl. später wieder benötigt werden. Hier sind es zum einen die Daten der Rechnung, zum anderen die des Kunden. Bei den Rechnungsköpfen sind alle dafür notwendigen Informationen bereits zeitlich fixiert. Bei den Rechnungspositionen werden wir aber fündig: Die Artikelnummer kann sich ändern (sie kann z.B. wegfallen), die Artikelbeschreibung auch und der Preis sowieso. Also legen wir folgende Attribute an:

Duplizieren zum Rechnungsstellungs-
zeitpunkt (RZ)

  • ArtNr-RZ (Artikelnummer zum RechnungsstellungsZeitpunkt)
  • Beschr-RZ (Beschreibung zum RZ)
  • Preis-RZ (Preis zum RZ)

Sie müssen nun in der Relation eingefügt werden, von deren Schlüssel sie funktional abhängig sind. Das ist RePos. Somit entsteht:

RePos-Historisch (#(ReNr, PosNr), ArtikelNr, Anzahl, ArtNr-RZ, Beschr-RZ, Preis-RZ)

Die Relation Artikel bleibt unverändert. Nun die Kundendaten. Hier kann sich auch sehr vieles verändern. Sämtliche Adressangaben, sogar der Nachname (wenn Herr Rumpelstiz den Namen seiner Frau annimmt). Somit entstehen folgende Attribute:

  • Name-RZ (Nachname zum RZ)
  • PLZ-RZ
  • Ort-RZ
  • Straße-RZ

Wohin mit diesen zeitlich fixierten Attributen? Da sie pro Rechnung genau einmal auftreten, sind sie von der Rechnungsnummer (ReNr) funktional anhängig und gehören in ReKöpfe:

ReKöpfe-Historisch (#ReNr, Datum, Verkäufer, KVDAT, Name-RZ, PLZ-RZ, Ort-RZ, Straße-RZ)

Damit sind die historischen Daten eingepflegt und der aktuelle Datenbestand der zeitlich abhängigen Attribute kann ohne Probleme weitergeführt werden. Insgesamt ergibt sich damit folgendes Datenmodell:

Adressen (#AdrNr, PLZ, Ort, Straße, Telefon)

Artikel (#ArtNr, Beschr, Preis)

KuAdr (#(KNr, AdressNr))

Kunden (#KNr, Name, Vorname)

ReKöpfe-Historisch (#ReNr, Datum, Verkäufer, KVDAT, Name-RZ, PLZ-RZ, Ort-RZ, Straße-RZ)

RePos-Historisch (#(ReNr, PosNr), ArtikelNr, Anzahl, ArtNr-RZ, Beschr-RZ, Preis-RZ)

Das gewünschte Ziel ist erreicht: Zum Rechnungstellungszeitpunkt werden die Artikelnummer, die Beschreibung und der Preis in die entsprechenden „RZ-Attribute“ geschrieben und bleiben dort erhalten.

15.3 Andere Lösungen

Stammdaten fortschreiben

Manchmal sieht man auch die folgende Lösung. Da bekommen die zeitabhängigen Attribute eine Versionsnummer. Bei Änderungen werden die vorhandenen Daten nicht überschrieben, sondern der neue Wert wird mit einer neuen Versionsnummer eischließlich der Zeitangabe dazugegeben.

In obigem Beispiel Artikel gilt dann: Wenn sich die Beschreibung ändert, erhält der Artikel eine neue Versionsnummer, ebenso wenn sich der Preis ändert, usw. Ein konkreter Artikel wird dann über die kombinierte Artikel- und Versionsnummer identifiziert:

Artikel (#(ArtikelNr, VersionsNr), Beschreibung, Preis)

Für die Rechnungspositionen ergibt sich dann:

RePos (#(ReNr, PosNr), (ArtikelNr, VersionsNr), Beschreibung, Preis, Anzahl)

Diese Lösung ist machbar, führt aber zu Redundanzen, nicht auf der Ebene der einzelnen Relationen, aber über die Relationen hinweg. So wird die Beschreibung wiederholt, wenn sich der Preis ändert. Hat sich nur der Preis geändert, z.B. zehn mal, wird in 10 Tupeln dieselbe Beschreibung und derselbe Standort festgehalten.

Binäre Relationen

Dies ist die Stelle, an der oft radikale Umstrukturierungen der Relationen vorgeschlagen werden im Sinne binärer Relationen. Das bedeutet, dass alle Attribute einer Relation, die sich im Zeitablauf verändern können, zusammen mit dem Schlüssel in jeweils eine eigene Relation getan werden. Im obigen Beispiel:

Artikel-Beschreibung (#(ArtikelNr, VersionsNr), Beschreibung)

Artikel-Preis (#(ArtikelNr, VersionsNr), Preis)

Die Relation zu den Rechnungspositionen würde sich bei dieser Lösung wie folgt verändern:

RePos (#(ReNr, PosNr), ((ArtikelNr, VersionsNr), Beschreibung), ((ArtikelNr, VersionsNr), Preis), ((ArtikelNr, VersionsNr), Anzahl))

Bei dieser Lösung sind die oben angesprochenen Redundanzen beseitigt, allerdings werden die Abfragen komplizierter. Nicht nur müssen mehr Relationen verknüpft werden, was die Abfragen und Auswertungen verlängert, es muss auch immer noch bei jeder Relation die höchste Versionsnummer (bzw. bei Rekonstruktionen die "richtige") bestimmt werden.

NoSQL-Welt

In der NoSQL und BigData-Welt werden andere Techniken angewandt. Z.B. bei Dokumentendatenbanken (vgl. Abschnitt 24.10). Hier wird nach jeder Änderung eines Feldes das gesamte Dokument als neue Version abgespeichert. Vgl. zu diesem Teil der Datenbankwelt Kapitel 24.