In diesem Abschnitt geht es um die Beziehungen zwischen den Attributen einer einzelnen Relation, nicht um die Beziehungen zwischen verschiedenen Relationen.

8.1 Einführung

Vereint modellieren

Die wichtigste Beziehung zwischen den Attributen einer einzelnen Relation ist die, dass sie zusammen die Objekte / Beziehungen der jeweiligen Objekt- oder Beziehungsklasse modellieren. So wie in der oben schon eingeführten Relation Aufträge modelliert werden. Daher rührt die Bezeichnung Relation für eine Tabelle, die diese Zusammengehörigkeit ausdrückt. Neben dieser fundamentalen Beziehung gibt es aber noch weitere, die bei der Optimierung der Relationen helfen.

Wichtigste Beziehung zwischen den Attributen einer Relation

Schließen, vom Einen auf das Andere

Betrachten wir obige Relation Aufträge_1NF nochmals und etwas genauer.

Aufträge_1NF

AuftrNr

PosNr

ProdNr

ProdBez

Menge

AuftrDatum

KuNr

KuName

0001

1

9901

Laser Dru x

1

30.06.15

1700

Müller

0001

2

9910

Toner xyz

3

30.06.15

1700

Müller

0001

3

9905

Papier abc

5.000

30.06.15

1700

Müller

0010

1

9905

Papier abc

30.000

01.07.14

1201

Sammer

0010

2

9910

Toner xyz

1

01.07.14

1201

Sammer

0011

1

9901

Laser Dru x

1

02.07.15

1600

Stanzl KG

0011

2

9911

Tintenpatr x

20

02.07.15

1600

Stanzl KG

0011

3

9905

Papier abc

5.000

02.07.15

1600

Stanzl KG

0011

4

9906

InkJet-Dru y

2

02.07.15

1600

Stanzl KG

0012

1

9998

z-Bildschirm

1

04.07.16

1900

Max OHG

...

 

 

 

 

 

 

 

Schlüssel: #(AuftrNr, PosNr)


Dann können wir feststellen, dass von bestimmten Attributen auf andere geschlossen werden kann (wobei die Grundlage dafür die Kenntnis der Semantik des jeweiligen Weltausschnitts ist). D.h., ist die Ausprägung des einen Attributs bekannt, kann die Ausprägung des anderen angegeben werden. Im obigen Beispiel ist dies in folgenden Fällen möglich:

Zusammenhang zwischen Attributen

  • Von der ProdNr kann auf die ProdBez geschlossen werden, und umgekehrt, wenn wir von der naheliegenden Tatsache ausgehen, dass beide - Produktnummern und Produktbezeichnungen - eindeutig sind.
  • Von der AuftrNr kann auf das AuftragsDatum geschlossen werden, weil ein Auftrag ein bestimmtes Datum hat.
  • Von der KuNr kann auf den KuName(n) geschlossen wer­den.
  • Von AuftrNr und PosNr zusammen(!) auf die ProdNr, die ProdBez(eichnung) und die Menge, da an einer Position eines Auftrags nur ein Produkt mit einer Mengenangabe aufgeführt wird.

Solche Beziehungen müssen nicht existieren. So kann z.B. weder von der AuftrNr auf die PosNr, noch von der ProdBez(eichnung) auf den KuName(n), usw. geschlossen werden. Wenn sie aber da sind, sind sie für die Modellierung von großer Bedeutung.

8.2 Funktionale Abhängigkeit

Sind nun aber zwischen Attributen oder Attributkombinationen solche "Schlüsse" möglich, wird von voller funktionaler Abhängigkeit (f.A.) gesprochen. Die Wortwahl ist folgende: Kann vom Attribut A auf das Attribut B "geschlossen" werden, ist B funktional abhängig von A.

In der textlichen Notation wird die volle funktionale Abhängigkeit mit dem grafischen Symbol "Pfeil mit Doppellinie" => dargestellt, also z.B. so:

=>

A => B (Attribut B ist funktional abhängig von Attribut A) oder

AuftrNr => KuNr

Alle bisher betrachteten funktionalen Abhängigkeiten sind sogenannte "volle". Auf die Unterscheidung von "voller" und "einfacher" f.A. wird weiter unten eingegangen.

Eine andere - gleichwertige - Interpretation der funktionalen Abhängigkeit ist es, die Attributsausprägungen zu betrachten: Gibt es für eine Ausprägung eines Attributs A für alle Tupel immer genau dieselbe für ein Attribut B, dann ist B funktional abhängig von A. Im obigen Beispiel:

Zweite Interpretation

  • Jedesmal, wenn in einem Tupel eine bestimmte Produktnummer auftritt, kommt dieselbe Produktbezeichnung vor. Dies gilt auch umgekehrt.
  • Jedesmal, wenn in einem Tupel eine bestimmte Auftragsnummer vorkommt, kommt dasselbe Auftragsdatum vor.
  • Jedesmal, wenn in einem Tupel eine bestimmte Kundennummer vorkommt, kommt derselbe Kundenname vor.
  • Für eine bestimmte Kombination aus Auftragsnummer + Positionsnummer gibt es genau eine Angabe zu Produktnummer, Produktbezeichnung und zur Menge.
  • Jedesmal wenn in einem Tupel eine bestimmte Auftragsnummer vorkommt, kommt dieselbe Kundennummer vor.

So kann funktionale Abhängigkeit also auch gesehen werden und manchen leuchtet diese Interpretation leichter ein als die obige. Beide Interpretationen ("schließen auf" bzw. "genau eines") sind aber gleichwertig. Einmal hilft bei der praktischen Modellierungsarbeit die eine, manchmal die andere.

Zwei Interpretationen

Basis der funktionalen Abhängigkeit

Das obige Beispiel macht auch deutlich, was die Voraussetzung für das Erkennen funktionaler Abhängigkeiten ist: das Wissen, das der Nutzer über den Anwendungsbereich und seine konkreten Objekte hat. Ohne dieses Wissen können die Relationen und dann das gesamte Datenmodell nicht konstruiert werden und dieses Wissen legt auch die funktionalen Abhängigkeiten fest.

Funktionale Abhängigkeit drückt Zusammengehörigkeit aus. Sie geht davon aus, dass es eine identifizierende Information gibt (bestehend aus einem Attribut oder mehreren), die jedes Tupel (d.h. Objekt oder Beziehung) identifiziert und weitere Attribute, die genau dieses Objekt oder diese Beziehung näher beschreiben.

Grundkonzept

In der relationalen Theorie wird dann noch zusätzlich verlangt, dass von den beschreibenden Attributen jeweils genau eine Ausprägung Gültigkeit hat.

Funktionale Abhängigkeiten einer Relation können auch grafisch dargestellt werden, durch ein sog. Diagramm der funktionalen Abhängigkeiten (FA-Diagramm). In ihm werden die Attribute durch Rechtecke repräsentiert und die funktionalen Abhängigkeiten durch Pfeile. Das folgende FA-Diagramm (in der US-amerikanischen Literatur FD-Diagram, wegen: functional dependency) zeigt die funktionalen Abhängigkeiten der obigen Relation Aufträge_1NF.


Abbildung 8.2-1:

FA-Diagramm der Relation Aufträge

Anmerkung: Jeder Pfeil repräsentiert eine volle funktionale Abhängigkeit.

Erläuterung

Für jedes Attribut wird ein Rechteck angelegt. Handelt es sich um einen Schlüssel, wird die Raute vorangesetzt:

Aufbau von FA-Diagrammen



Besteht ein Schlüssel aus zwei oder mehr Attributen, wird um diese ein weiteres Rechteck gezeichnet:



Die Pfeillinien zwischen den Attributen bedeuten jeweils eine funktionale Abhängigkeit. D.h. von dem Attribut am Pfeilanfang kann auf das Attribut an der Pfeilspitze geschlossen werden. So wie hier von der Kundennummer auf den Namen des Kunden:



Ob es sich um eine volle oder einfache funktionale Abhängigkeit handelt, geht aus dem FA-Diagramm hervor. Das für das Erkennen notwendige Instrumentarium wird in den nächsten Abschnitten vorgestellt. Ganz grundsätzlich gilt im übrigen, dass alle Attribute einer Relation in irgendeiner Form mit anderen verbunden sein müssen.

Idealstrukturen

Die Bedeutung der funktionalen Abhängigkeiten liegt auch darin, dass man die Anforderung an korrekte und redundanzfreie Relationen grafisch darstellen kann. Dadurch wird jede Abweichung sofort in der Abbildung sichtbar.

Strukturierungshinweis durch funktionale Abhängigkeiten

Korrekt und redundanzfrei sind Relationen, wenn sie einen Schlüssel haben (oder auch mehrere konkurrierende) und wenn alle anderen Attribute vom Schlüssel voll funktional abhängig sind. Die folgenden Abbildungen zeigen solche - abstrahierten - Idealstrukturen am Beispiel von vier Attributen [Anmerkung] und einem Schlüssel (mit einem Attribut bzw. mit zweien).


Abbildung 8.2-2:

Idealstruktur 1 - Relation ohne Redundanz und Anomalien


Abbildung 8.2-3:

Idealstruktur 2 - Relation ohne Redundanz und Anomalien mit zusammengesetztem Schlüssel

Anmerkung: Das Rechteck um die beiden Schlüsselattribute kennzeichnet diese als Schlüssel.

Ziel der Normalisierung

Liegen nun von dieser Idealstruktur abweichende funktionale Abhängigkeiten vor, sind sie in der Abbildung sofort erkennbar und können beseitigt werden. Im Rahmen der weiteren Normalisierungsschritte geht es nun darum, für jede Relation - ohne Informationsverlust - eine solche Idealstruktur zu erreichen.

Determinanten

Bevor wir dies vertiefen, soll noch ein weiterer Begriff eingeführt werden: Determinante. Jedes Attribut, von dem andere funktional abhängig sind, wird Determinante genannt. Determinanten können auch aus mehreren Attributen bestehen, wie im obigen Beispiel: Hier sind AuftrNr und PosNr zusammen Determinante für ProdNr und weitere Attribute. Natürlich sind alle Schlüssel auch Determinanten. Damit liegen insgesamt folgende "Rollen" von Attributen in Relationen vor:

  • Schlüssel
  • Teil eines zusammengestzten Schlüssels, diese werden Schlüsselattribute(SA) genannt
  • Attribute, die nicht Teil eines Schlüssels sind, diese werden Nichtschlüsselattribute(NSA) genannt
  • Determinanten

Der Weg zur oben angedeuteten "Idealstruktur" kann dann auch so beschrieben werden, dass durch sie jeweils eine Determinante und die von ihr funktional abhängigen Attribute zu einer Relation werden, wobei die Determinante dann Schlüssel wird.

Zur Veranschaulichung hier eine Abbildung, die im FA-Diagramm der Relation Aufträge_1NF die Determinanten (D), die Schlüsselattribute (SA) und die Nichtschlüsselattribute (NSA) markiert.


Abbildung 8.2-4:

Schlüsselattribute (SA), Nichtschlüsselattribute (NSA) und Determinanten (D) in Aufträge_1NF

Jetzt wird deutlich, dass die oben angesprochenen Strukturdefizite zwei Ursachen haben:

1) Die Tatsache, dass einzelne Schlüsselattribute Determinanten sind.

Dies führt immer zu Redundanz, die Beseitigung dieses Defizits wird zur 2NF führen. Der Grund ist folgender: Die Ausprägungen eines einzelnen Schlüsselattributs kommen in der Regel jeweils mehrfach vor. Damit kommen auch die Ausprägungen des funktional abhängigen Attributs mehrfach vor. Im obigen Beispiel: AuftrNr hat Ausprägungen, die gleich sind (die eines Auftrags). Für alle diese gleichen Ausprägungen wird die KuNr erfasst. Damit sind die erfassten Daten redundant.

2) Die Tatsache, dass es Determinanten gibt, die Nichtschlüsselattribute sind.

Auch dies erzeugt immer Redundanz, die Beseitigung dieses Defizits führt zur 3NF. Der Grund: Die Ausprägungen von Nichtschlüsselattributen kommen natürlich mehrfach vor und damit auch die Ausprägungen der funktional abhängigen Attribute. Im obigen Beispiel: KuNr hat gleiche Ausprägungen (für die Aufträge von einem Kunden). Damit wird auch der KuName mehrfach erfasst.

8.3 Schneller Weg zum Erfolg

Ein schneller Weg zum Erreichen der Idealstruktur (der höchsten Normalform), der allerdings erst nach einiger Übung leicht fällt, besteht darin, aus jeder Determinante und den von ihr abhängigen Attributen eine eigene Relation zu machen und die dabei entstehenden Relationen dann noch durch Fremdschlüssel zu verknüpfen. Nimmt man die in diesem Beispiel vorliegenden vier Determinanten

Beispiel "Aufträge"
Zerlegung in 4 Relationen

AuftrNr

KuNr

ProdNr bzw. ProdBez

und

(AuftrNr, PosNr)

kann man, sozusagen auf direktem Weg, durch Bildung von vier Relationen zur "Idealstruktur" kommen. Beachtet werden muss lediglich, dass bei der notwendigen Zerlegung die Verknüpfbarkeit erhalten bleibt. Im folgenden sind die dabei entstehenden Relationen in Tabellenform angegeben. Um die Beseitigung der Redundanz deutlich zu machen, wurden die in den neuen Relationen wegfallenden Tupel durchgestrichen stehen gelassen.

Die neuen Relationen sind bereits in der höchsten Normalform, der 5NF.

AuftrKöpfe_5NF

AuftrNr

AuftrDatum

KuNr

0001

30.06.15

1700

0001

30.06.15

1700

0001

30.06.15

1700

0010

01.07.14

1201

0010

01.07.14

1201

0011

02.07.15

1600

0011

02.07.15

1600

0011

02.07.15

1600

0011

02.07.15

1600

0012

04.07.16

1900

...

 

 

Schlüssel: #AuftrNr


In obiger Relation wird die KuNr zum Fremdschlüssel. Jetzt wurde nur noch ein einziges Mal erfasst, dass die Auftragsnummer 0001 das Auftragsdatum 30.06.15 hat, usw.

Kunden_5NF

#KuNr

KuName

1700

Müller

1700

Müller

1700

Müller

1201

Sammer

1201

Sammer

...

 


Dass zur Kundennummer 1700 der Kunde Müller gehört, ist jetzt nur noch einmal in der Datenbank vermerkt.

Produkte_5NF

#ProdNr

#ProdBez

...

 

9901

Laser Dru x

9901

Laser Dru x

9905

Papier abc

9905

Papier abc

9905

Papier abc

9906

InkJet-Dru y

9910

Toner xyz

9910

Toner xyz

9911

Tintenpatr x

9998

z-Bildschirm

...

 

Schlüssel: #ProdNr, #ProdBez


Die Tatsache, dass "Papier abc" die Produktnummer 9905 hat, wird jetzt nur noch einmal erfasst.

AuftrPos_5NF

AuftrNr

PosNr

ProdNr

Menge

0001

1

9901

1

0001

2

9910

3

0001

3

9905

5.000

0010

1

9905

30.000

0010

2

9910

1

0011

1

9901

1

0011

2

9911

20

0011

3

9905

5.000

0011

4

9906

2

0012

1

9998

1

...

 

 

 

Schlüssel: #(AuftrNr, PosNr)


Hier müssen keine Zeilen durchgestrichen werden. Dieser Teil der Relation war bereits frei von Redundanz, da hier alle Nichtschlüsselattribute (NSA) voll funktional abhängig sind vom Gesamtschlüssel. ProdNr wird zum Fremdschlüssel, der diese Relation mit der Relation Produkte verknüpft. AuftrNr verknüpft mit AuftrKöpfe.

Somit zeigt sich, dass in der Ausgangsrelation Aufträge_1NF vier verschiedene Aspekte der Realwelt modelliert waren: die Beziehung zwischen Aufträgen und Kunden, die Kunden, Produkte und Auftragspositionen.

Vermischung verschiedener Objekte / Relationen

Bei jeder solchen Neuordnung muss dann noch geprüft werden, ob die Zerlegung nicht zu einem Informationsverlust geführt hat. Dazu muss lediglich überprüft werden, ob die neuen Relationen durch Attribute wieder verknüpft werden können oder ob vielleicht das eine oder andere Attribut als Fremdschlüssel ergänzt werden muss, bzw. ob eine Verbindungsrelation nötig ist. Hier ergaben sich die Fremdschlüssel von selbst, dies ist aber nicht immer so.

Die grafische Darstellung des Datenmodells Aufträge_5NF gibt den Zusammenhang zwischen den Relationen an:


Abbildung 8.3-1:

Datenmodell Aufträge

Abschließend noch die textliche Notation dieses Datenmodells:

AuftrKöpfe_5NF (#AuftrNr, AuftrDatum, KuNr)

AuftrPos_5NF (#(AuftrNr, PosNr), ProdNr, Menge)

Kunden_5NF (#KuNr, KuName)

Produkte_5NF (#ProdNr, #ProdBez)

Im Rahmen der Datenbanktheorie wird diese "Idealform" durch zwei Normalisierungsschritte (2NF und 3NF) erreicht, die im Folgenden vorgestellt werden. Bevor wir uns dem zuwenden, muss noch die Unterscheidung von einfacher und voller funktionaler Abhängigkeit eingeführt werden.

8.4 Einfache und volle FA

Alle bisherigen funktionalen Abhängigkeiten waren sogenannte "volle". Zur Einführung der "einfachen" betrachten wir nochmals die ursprüngliche Relation Aufträge_1NF, die den Schlüssel #(AuftrNr, PosNr) hat. Von diesem Schlüssel kann - sonst wäre es kein Schlüssel - auf alle übrigen Attribute geschlossen werden, wenn auch auf unterschiedliche Weise. Die folgende Liste gibt all diese Abhängigkeiten an, die vollen f.A. sind mit => gekennzeichnet:

f.A. = funktionale Abhängigkeit

AuftrNr, PosNr => ProdNr (volle f.A.)

AuftrNr, PosNr => ProdBez (volle f.A.)

AuftrNr, PosNr => Menge (volle f.A.)

AuftrNr, PosNr --> AuftragsDatum (einfache f.A.)

AuftrNr, PosNr --> KuNr (einfache f.A.)

AuftrNr, PosNr --> KuName (einfache f.A.)

Wie zu sehen ist, liegen nun Abhängigkeiten vor, die nicht volle f.A. sind. Dies sind einfache funktionale Abhängigkeiten. Sie werden in den Abbildungen mit einem einfachen Pfeil --> gekennzeichnet.

Bei diesen ist die Determinante "überausgestattet", d.h., sie weist mehr Attribute auf, als für die volle funktionale Abhängigkeit nötig wäre. In den obigen drei Fällen einfacher funktionaler Abhängigkeit würde z.B. das Attribut AuftrNr alleine für eine volle funktionale Abhängigkeit ausreichen. Somit gilt:

Determinante überausgestattet

Eine funktionale Abhängigkeit heißt voll, wenn von der Determinante kein Attribut weggenommen werden kann, ohne dass die funktionale Abhängigkeit verloren geht.

Definition:
Volle und einfache funktionale Abhängigkeit (f.A.)

Sie heißt einfach, wenn die Determinante mehr Attribute enthält, als für die funktionale Abhängigkeit nötig ist.

Im obigen Beispiel gelten darüberhinaus auch noch die sozusagen trivialen einfachen funktionalen Abhängigkeiten von der Determinante auf ihre Teile:

AuftrNr, PosNr --> AuftrNr

AuftrNr, PosNr --> PosNr

Diese sollen allerdings im weiteren nicht betrachtet werden.

Formale Definition: einfach und voll

Nun zu einer formalen Definition der funktionalen Abhängigkeiten. Diese bezieht sich darauf, dass das Vorkommen eines Werts eines Attributs (bzw. einer Attributkombination) AK1 über alle Tupel hinweg mit dem Vorkommen eines bestimmten Werts eines Attributs (oder einer Attributkombination) AK2 verbunden sein kann. Die erste Definition beschreibt funktionale Abhängigkeit als solche, noch ohne die Unterscheidung in "volle" oder "einfache".

Seien T die Menge der Attribute einer Relation und AK1, AK2 Teilmengen von T, d.h.

Definition (formal):
funktionale Abhängigkeit (f.A.)

AK1 = {A11, A21, A31, ..., Am1}, AK2 = {A12, A22, A32, ..., An2}.

AK2 ist funktional abhängig von AK1 (in der jeweiligen Relation), in Zeichen: AK1 --> AK2, falls gilt: alle Tupel, die in den AK1-Ausprägungen übereinstimmen, tun dies auch in den AK2-Ausprägungen.

Eine Attributkombination (AK) besteht aus einem oder mehreren Attributen von T, der Menge der Attribute einer Relation. Nachfolgende Definition der vollen funktionalen Abhängigkeit erfasst nun den Tatbestand, dass die Determinante nur die Minimalausstattung an Attributen haben sollte.

Seien AK1, AK2 Teilmengen von T. AK2 heißt voll funktional abhängig von AK1, in Zeichen: AK1 => AK2, falls gilt:

Definition (formal):
volle f.A.

1) AK1 -->AK2

und

2) Es gibt keine echte Untermenge AK1* von AK1, so dass gilt:

AK1* --> AK1

Ist AK1 ein einziges Attribut, dann ist AK1 --> AK2 gleichbedeu­tend mit

AK1 => AK2

Als einfache funktionale Abhängigkeit soll hier weiterhin eine funktionale Abhängigkeit bezeichnet werden, die keine volle ist.

Hier noch ein weiteres Beispiel, eine Relation, die recht einfach die Mitarbeit von Angestellten in Projekten erfasst. Wie immer soll die Semantik gelten, dass ein Angestellter in mehreren Projekten mitarbeiten kann und ein Projekt mehrere ihm zugewiesene Angestellte hat. In einer Relation

Beispiel Projektmitarbeit

Angestellte (#(PersNr, BezProj), ProgSpr, AntProj)

(mit Personalnummer; Projekt, in dem der/die Angestellte mitarbeitet; Programmiersprachen, die ein Angestellter beherrscht; Anteil der Arbeitszeit, die ein Angestellter für ein Projekt tätig ist) gelten dann folgende funktionalen Abhängigkeiten:

PersNr, BezProj --> ProSpr

PersNr, BezProj => AntProj

PersNr => ProgSpr

Das FA-Diagramm ergibt sich dann wie folgt:


Abbildung 8.4-1:

FA-Diagramm der Relation Angestellte

Die funktionale Abhängigkeit des Attributs ProgSpr vom Schlüssel ist nur eine einfache, da als Determinante die PersNr alleine genügen würde.

8.5 Schlüssel (formal)

Weiter oben wurde ein Schlüssel kurz als ein Attribut definiert, das für jedes Objekt (für jedes Tupel) eine andere Ausprägung hat, dessen Ausprägungen, m.a.W., paarweise verschieden sind. Damit gleichbedeutend ist, dass ein Schlüssel die eindeutige Identifikation aller Objekte (Datensätze) erlaubt. Dies kann nun präziser gefasst werden:

Sei AK Teilmenge von T, d.h. AK = {A1, A2, ..., An}. AK heißt Schlüssel, falls für alle Am (Am NICHT enthalten in T) aus der Relation R gilt:

Schlüssel: Definition 4

A1, A2, ..., An => Am
und keine echte Untermenge von AK hat diese Eigenschaft.

Damit gilt (mit AK1 und AK2 als Attributskombinationen einer Relation):

AK1 Schlüssel ==> AK1 => AK2

D.h., falls AK1 ein Schlüssel ist, sind alle anderen Attributskombinationen davon voll funktional abhängig.

AK1, AK2 Schlüssel ==> AK1 => AK2 und AK2 => AK1.

Erinnerung:

1. Das Zeichen '==>' meint hier die logische Implikation. Damit bedeutet A ==> B: aus A folgt B.

2. T: Menge der Attribute einer Relation

3. Attributskombination AK: Attribute einer Relation, z.B. die eines zusammengesetzten Schlüssels

Liegen zwei Schlüssel vor, sind diese natürlich gegenseitig voneinander funktional abhängig. Wie oben schon angeführt, werden Attribute, die Teil eines Schlüssels sind, Schlüsselattribute (SA) genannt. Die anderen Nichtschlüsselattribute (NSA).