Matthiesen

Werbung
*)
3.3 Relationenalgebra
Die Beispiele können mit der dem Buch beigefügten Datenbank nachvollzogen werden. Am Schluss
dieses Skripts sind die darin enthaltenen Tabellen abgedruckt, sodass man auch ohne Computer die
Beispiele nachvollziehen kann.
In der Relationenalgebra werden aus vorhandenen Relationen neue Relationen erzeugt. In den
Abfragesprachen der kommerziell verfügbaren Datenbanksysteme (z. B. in SQL) sind Konstruktionen
enthalten, die die Operationen der Relationenalgebra realisieren. Wir benutzen hier eine kompakte
Sprache, die im Gegensatz zu SQL die einzelnen Operationen der Relationenalgebra direkt beschreibt.
Diese neuen Relationen können in folgender Weise verwandt werden:
Snapshot
Es wird eine neue Relation (im Hauptspeicher oder auf der Platte) angelegt, die aus den aktuell
gültigen Daten abgeleitet wird. Auf diese Relation kann anschließend zugegriffen werden.
Zwischenzeitliche Änderungen in den benutzten Ursprungsdaten bleiben dabei unberücksichtigt.
Datenausgabe
Die erzeugte Relation wird lediglich auf dem Bildschirm, Drucker oder in eine Datei ausgegeben und
kann anschließend vom Datenbanksystem nicht mehr verarbeitet werden.
Virtuelle Datensicht
Die neue Relation wird nicht sofort angelegt, sondern bei jedem Zugriff auf diese Datensicht wird sie
aus den aktuell gültigen Daten erzeugt; diese Relation muss daher auch nicht gespeichert werden.
3.3.1 Die Auswahl (Selektion)
Sei R eine Relation, bedingung sei ein logischer Ausdruck (entsprechend einem Booleschen Ausdruck
in Programmiersprachen wie Pascal), der aus Attributbezeichnern von R (als Variablen), aus
Konstanten, aus den entsprechenden Operatoren und Funktionen, aus den Vergleichsoperatoren =, ≠, <,
≤, > , ≥, aus den logischen Operatoren ∧, ∨, ¬
gebildet wird.
Durch
Sel [bedingung] (R)
wird eine Relation definiert, die genau die Tupel enthält, die die Bedingung erfüllen (d. h. für die der
Boolesche Ausdruck den Wert TRUE ergibt).
Der einfachste Fall der logischen Bedingung ist der Des weiteren können mehrere Attribute
miteinander verglichen werden, z. B.
Vergleich eines Attributes mit einer Konstanten
der entsprechenden Domäne, z. B.
Ankunft < Abfahrt
Name = 'Meyer'
Listenpreis < 100,00 DM
Ankunft < TIME '12:00'
Ort ≠ 'Bremen'
Listenpreis > Einkaufspreis
Wohnort ≠ Arbeitsort
*)
Dieses Skript ist ein Auszug aus dem Kapitel 3.3 (Seite 79ff) von: Matthiessen, G., Unterstein,
M. Relationale Datenbanken und SQL, Addison-Wesley Verlag, 1997, ISBN 3-8273-1167-5
1
Bedingungen können des weiteren mit logischen
Operatoren verknüpft werden, z. B.
Schließlich können in die Vergleiche auch
berechnete Ausdrücke eingehen, wie z. B.
Wohnort = 'Bremen'
∨ Arbeitsort 'Bremen'
Name = 'Matthiessen'
∧ Vorname 'Günter'
Ankunft + TIME'0:08' < Abfahrt
Länge < 1,41 * Breite ∧ Länge <235 mm
∧ Breite ≤ 125mm ∧ Höhe ≤ 5mm ∧
Gewicht ≤ 20 g
Beispiel
Relation, die die Artikel enthält, die nachbestellt werden müssen:
Sel[Bestand]< Mindestbestand] (Artikel)
Beispiel
Relation, die die Kunden aus dem PLZ-Bezirk 23863 sowie die Kunden aus Husum enthält:
Sel [PLZ = '23863' v Ort = 'Husum'] (Kunde)
Eine Selektion besteht also darin, dass in einer Relation einige Zeilen gestrichen
werden und nur die übrigbleiben, die die angegebene Bedingung erfüllen:
Im Spezialfall dient die Selektion auch dazu, einen einzelnen Satz zu selektieren, indem ein eindeutiges
Merkmal angegeben wird (z. B. der Schlüssel). Falls dieses Merkmal dann nicht in der Relation
vorhanden ist, erhalten wir als Ergebnis die leere Relation, die also nur aus den Spaltenüberschriften
besteht.
Beispiel
Relation, die genau das Tupel mit den Kundendaten 103 enthält.
Sel[Kunden-Nr = 1031 (Kunde)
2
Beispiel
Relation, die genau das Tupel mit den Kundendaten des Kunden 128 enthält.
Sel[Kunden-Nr = 1281 (Kunde)
Es handelt sich hierbei um eine leere Relation, die aussagt, dass kein Tupel die geforderte Bedingung
erfüllt.
3.3.2 Die Projektion
Sei R eine Relation und {r1,..., rm} eine Teilmenge der Attribut-Bezeichner von R. Dann ist
Proj[r1,..., rm] (R)
Eine Relation mit den Attributbezeichnern {r1,..., rm}, die für jedes Tupel t∈R genau ein Tupel [t.r1,...,
t.rm] enthält (Tupel, die mehrfach auftreten, werden einfach gezählt!). Das heißt, es zählt nur die
Information der angegebenen Attribute - die übrigen Attribute werden ignoriert.
Dadurch können Tupel der Relation R zusammenfallen, wenn sie nämlich in allen Attributen r1,..., rm,
übereinstimmen, sich aber in mindestens einem Attribut das nicht in der Projektion auftritt,
unterscheiden.
Beispiel
Relation, die für jeden Artikel neben der Artikelnummer und der Bezeichnung den Lagerplatz und den
Bestand angibt (Bestandsliste).
Proj[Artikel_Nr,Bezeichnung,Lagerplatz,Bestand](Artike1)
Beispiel
Relation, die alle Orte mit PLZ enthält in denen Kunden wohnen. Hierbei tauchen Orte mit mehreren
Kunden nur einmal auf.
Proj[plz, ort] (Kunde)
3
Die Projektion besteht also darin, dass gewisse Spalten ausgeblendet werden; nur
die angegebenen Spalten bleiben übrig. Dabei kann es als Folgeaktion notwendig
werden, bei mehrfach auftretenden identischen Zeilen jeweils alle bis auf eine zu
streichen.
3.3.3 Umbenennung von Attributbezeichnern
Die Umbenennung von Attributen ist in folgenden Fällen notwendig:
1. Änderung der Überschrift einer auszugebenden Tabelle
2. Zwei Tabellen sollen miteinander verknüpft werden (wird in Kapitel 3.3.6 eingeführt), dazu müssen
die korrespondierenden Attribute in den beiden Relationen jeweils denselben Bezeichner haben.
3. Zwei Tabellen sollen miteinander verknüpft werden, dazu müssen die nicht korrespondierenden
Attribute in den beiden Relationen jeweils unterschiedliche Bezeichner haben.
Wenn a ein Attribut einer Relation R ist und b ein Bezeichner, der nicht als Attributbezeichner von R
auftritt, wird durch
Ren[b ::= a] (R)
eine Relation definiert, in der das Attribut a jetzt b heißt.
Falls mehrere Umbenennungen erfolgen, schreiben wir diese hintereinander in eckige Klammern, wie in
folgendem Beispiel.
Ren [KNr ::= Kunden_Nr, St ::= Status,
Lbest ::= letzte_Bestellung,
Lwerb ::= letzte_Werbung,
ZArt ::= Zahlungsart]
(Kunde)
4
Da eine Umbenennung häufig im Zusammenhang mit einer Projektion erfolgt, schreiben wir in Zukunft
als Kurzschreibweise die umbenannten Attribute in die Liste der Projektionsattribute mit hinein. Die
umbenannten Attribute sind grundsätzlich mit in die Liste der zu projizierenden Attribute einzubeziehen
(sonst bräuchten wir sie ja nicht erst umzubenennen). So wird
Proj[ArtNr,Bezeichnung,Lager,Ist]
(
Ren[ArtNr::=Artikel_Nr, Lager::=Lagerplatz, Ist::=bestand] (Artikel)
)
zu
Proj[ArtNr::=Artikel_Nr, Bezeichnung,
Lager::=Lagerplatz,
Ist::= bestand](Artikel)
3.3.4 Adjunktion virtueller Spalten
Sei R eine Relation und sei a ein Ausdruck, der aus
Attributbezeichnern der Relationen und
Operationen, die für die Domänen definiert sind, sowie
Konstanten
gebildet ist und s sei ein Bezeichner, der nicht als Attributbezeichner in R auftritt; dann wird durch
Adj[s ::= a] (R)
eine Relation definiert, die eine zusätzliche Spalte enthält, in der als Wert jeweils die Auswertung von a
enthalten ist. Diese Spalte wird als virtuelle Spalte bezeichnet.
Für ein Tupel t hängt also der Wert von s von den Werten der (echten) Attribute ab. Üblicherweise wird
daher der Wert von s nicht mit in der Datenbank gespeichert, sondern bei jedem Aufruf neu berechnet.
5
Auch hier übernehmen wir üblicherweise die adjungierten Spalten mit in die Projektionsattribute, vgl.
hierzu das folgende Beispiel.
Beispiel
Relation, die für jeden Artikel die angegebenen Attribute sowie das Produkt aus Bestand und
Listenpreis enthält.
Proj[ArtNr, Bezeichnung, Bestand, Listenpreis, Wert]
(
Ren[ArtNr ::= Artikel_Nr]
(
Adj[Wert ::= Bestand * Listenpreis] (Artikel)
)
)
oder kürzer:
Proj[ArtNr ::= Artikel_Nr,
Bezeichnung, Bestand, Listenpreis,
Wert ::= Bestand * Listenpreis] (Artikel)
3.3.5 Gruppierung von Daten
Wie wir gesehen haben, werden bei der Projektion gegebenenfalls mehrere Tupel jeweils
zusammengefasst: wenn sie in den Projektionsattributen identisch sind, sich aber in anderen Attributen
noch unterscheiden. Hier bilden die Tupel, die in den Projektionsattributen identische Werte haben,
jeweils eine Datengruppe, wobei die Werte in den nicht projizierten Attributen unterschiedlich sein
können. Häufig möchten wir für diese Datengruppen weitere Werte haben, die sich aus den Tupeln der
jeweiligen Gruppen berechnen lassen. Im einfachsten Fall möchten wir nur die Anzahl der Tupel der
jeweiligen Gruppen haben. Des weiteren möchten wir z.B. die Summen der in den einzelnen Lagern
wissen.
In diesen Fällen verwenden wir statt der Projektion die
Datengruppierung. Zusätzlich zu den zu projizierenden
Attributen hat die neue Relation weitere adjungierte Attribute,
die durch die Anwendung von Aggregatfunktionen auf die
Attribute, die nicht in der Projektion auftreten, entstehen.
Formal schreiben wir die Anwendung der Aggregatfunktionen
hinter die Projektionsattribute, durch einen senkrechten Strich
getrennt.
Die Aggregatfunktion COUNT(*)ergibt für jede Datengruppe
die Anzahl ihrer Tupel. Die weiteren Aggregatfunktionen haben jeweils eine Spalte oder virtuelle Spalte
als Argument. Als Aggregatfunktionen können beliebige Funktionen auftreten, die Mengen von Werten
6
als Argumente annehmen. In SQL sind das neben COUNT(*) folgende Aggregatfunktionen, die als
Argument jeweils ein Attribut annehmen (z. B. SUM (Bestand)):
COUNT
Anzahl definierter Werte
COUNT DISTINCT
Anzahl verschiedener Werte
SUM
Summe
AVG
Average, Durchschnitt
MIN
Minimum
MAX
Maximum
Als weitere Funktionen (die nicht in SQL definiert sind) kämen z.B. noch das Produkt von numerischen
Werten oder statistische Kenngrößen wie Varianz, Median oder geometrisches Mittel in Frage.
Beispiel
Die folgende Relation gibt für jeden Lagerplatz die Summe der Artikel-Bestände an.
Grp[Lagerplatz | Gesamtbestand ::= SUM(Bestand)] (Artikel)
Beispiel
Relation aller Lagerplätze, die einen Bestand von höchstens 1000 haben:
Sel[Gesamtbestand < 1000]
(Grp[Lagerplatz | Gesamtbestand::=SUM(bestand)] (Artikel)
An diesem Beispiel ist zu beachten, dass hier die Selektion nach der Gruppierung durchzuführen ist.
Beispiel
Im folgenden Beispiel tritt sowohl eine Selektion auf Tupel-Ebene als auch eine Selektion auf
Gruppenebene auf. Es werden nur die selektierten Tupel in die Gruppe aufgenommen und anschließend
die relevanten Gruppen ausgewählt: Wir wollen eine Liste der Lager mit dem jeweiligen Gesamtbestand
haben, wobei wir uns nur für Artikel interessieren, die mindestens für 5,00 DM verkauft werden und nur
für Lager, in denen der Gesamtbestand dieser Artikel höchstens 1000 ist.
Sel[Gesamtbestand < 1000]
(
Grp[Lagerplatz | Gesamtbestand ::= SUM(bestand)]
(
Sel[Listenpreis > 5.00] (Artikel)
))
7
Ein Sonderfall der Datengruppierung tritt auf, wenn kein Gruppierungsattribut angegeben wird, sondern
nur Aggregatfunktionen. In diesem Fall werden die Aggregatfunktionen auf die gesamte Tabelle
angewandt. So eine Relation hat naturgemäß nur ein Tupel.
Grp[ | Gesamtwert ::= SUM(Bestand * Listenpreis),
MaxBestand ::= MAX(Bestand),
MinPreis ::= MIN(Listenpreis),
Sortiment ::= COUNT(Artikel_Nr)] (Artikel)
In diesem Fall können wir Varianten der Aggregatfunktionen definieren, die als Ergebnis keine Relation
liefern, sondern einen Wert. So ist
SUM(Bestand * Listenpreis;Artikel) = 56722,51 DM
MAX(Bestand;Artikel) = 2101
MIN(Listenpreis;Artikel) = 0,98
COUNT(Artikel-Nr;Artikel) = 12
Ein weiterer Sonderfall ist gegeben, wenn hinter dem senkrechten Strich keine Anwendung einer
Aggregatfunktion steht - in diesem Fall ist die Datengruppierung nichts anderes als die normale
Projektion1
3.3.6 Der Verbund (Join)
Der Verbund ist eine sehr wichtige Operation im relationalen Datenbankmodell, da durch ihn die
Möglichkeit gegeben ist mehrere Relationen miteinander zu verknüpfen. In dieser abstrakten
Darstellung des relationalen Datenmodells betrachten wir in erster Linie den sog. natürlichen Verbund
(engl. natural join). Hieraus können wir den allgemeineren Gleichheits-Verbund (equi join) erhalten,
indem wir gegebenenfalls vorher die entsprechenden Attribute umbenennen. Den noch allgemeineren
Verbund (Θ-Join im Sinne von Codd, wobei Θ für eine beliebige zweistellige Operation wie =, <, ≤, >,
≥ steht) behandeln wird hier nicht weiter, da er als Selektion auf dem Kreuzprodukt dargestellt werden
kann und außerdem in der Praxis nur eine geringe Rolle spielt.
Wie merken hier an, dass der natürliche Verbund, wie wir ihn hier einführen, für die theoretische
Definition der Relationenalgebra hervorragend geeignet ist da er einfacher zu definieren ist als die
anderen Verbund-Operationen. In der Praxis hat der natürliche Verbund allerdings einen sehr großen
Nachteil: er ist empfindlich gegen nachträgliche Änderungen des Datenbankschemas. Da sich die
Verknüpfung auf alle Attribute bezieht, die (absichtlich oder zufälligerweise) in beiden Relationen
auftreten, kann durch die Einführung eines neuen Attributes (z. B. mit der Bezeichnung Bemerkung),
das eigentlich mit der geplanten Verknüpfung nichts zu tun hat, das Ergebnis völlig geändert werden: es
werden dann keine Tupel mehr verknüpft, da z. B. die Bemerkungen in der Bestell-Relation nicht mit
den Bemerkungen in der Kunden-Relation übereinstimmen.
Folgende Voraussetzungen müssen gegeben sein, damit ein Verbund definiert werden kann:
1. R und S sind Relationen;
2. a1,... an sind genau die Attribut-Bezeichner, die in R und S vorkommen (also Durchschnittsmenge
der Attributbezeichner);
1
So ist in dem relationalen Datenbanksystem Microsoft Access in einer Abfrage eine Projektion formal
als Gruppierung zu beschreiben.
8
3. für i = 1. . n sind die Domänen von ai in R und in S jeweils kompatibel, d. h. sie sind identisch oder
es ist zumindest möglich, Werte dieser entsprechenden Domänen auf Gleichheit zu überprüfen;
4. die übrigen Attribut-Bezeichner von R und S sind jeweils verschieden.
Die Bedingungen 2 und 4 sind gegebenenfalls durch Umbenennungen von Attributen zu erzwingen. An
dieser Stelle ist die Operation der Umbenennung essentiell.2
Es ist dann
R Join[a1,... an] S
eine neue Relation, die wie folgt definiert ist:
1. Die Attribute von R Join[a1,... an] S sind genau die Attribute von R und S.
2. Die Verbindungsattribute a1,... an werden also genau einmal gezählt.
3. R Join[a1,... an] S enthält für alle Paare von Tupeln von r ∈ R und s ∈ S, die für alle Attribute von
a1,... an definiert sind und jeweils identische Werte besitzen, jeweils das Tupel r+s.
4. Da nach der Voraussetzung für zu verknüpfende r und s alle Attribute von a1,... an identische Werte
besitzen, sind r und s widerspruchsfrei und somit ist r+s definiert.
Ein Tupel r ∈ R kann mit einem Tupel s ∈ S, mit mehreren Tupeln s ∈ S oder mit keinem Tupel s ∈ S
verbunden werden.
Beispiel
Bestellung Join[Kunden_Nr] Kunde
Diese Relation enthält für jedes Tupel der Relation »Bestellung« die Angaben (Bestell-Nr,
Bestelldatum, Lieferdatum, Rechnungsbetrag) sowie alle Kundendaten für die entsprechenden Kunden.
Falls allerdings eine in der Relation »Bestellung« angegebene Kundennummer in der Relation »Kunde«
nicht enthalten ist, wird diese Bestellung - ohne Warnung - ignoriert. (Dies kann nicht auftreten, da wir
als Konsistenzbedingung eine referentielle Konsistenz angegeben haben - hier sehen wir auch, wozu
diese referentielle Konsistenz wichtig ist).
Graphisch können wir diese Verknüpfung auch in folgender Form darstellen, indem wir die zu
verknüpfenden Attribute durch eine Linie verbinden:
2
In XBase fehlt diese Operation. Die Join-Anweisung enthält zwar die Möglichkeit, entsprechend
Punkt 2 die Verbindungsbedingung zu formulieren, aber gleichnamige Feld-Bezeichner können
nicht umbenannt werden. Somit sind die Operationen der Relationenalgebra in Xbase nicht
vollständig formulierbar (außer durch explizite Programmierung mit verschachtelten
Programmschleifen - das können wir aber auch in jeder >~normalen<~ Programmiersprache).
9
Beispiel (Self Join)
Verbindungen müssen nicht immer über Schlüsselattribute hergestellt werden. Durch entsprechende
Umbenennung können auch Relationen mit sich selber verknüpft werden. Hierzu sei die folgende
Relation »Kaiser« gegeben:
Kaiser
Durch
Proj[A_Name::=Name, Vater] (Kaiser)
Join[Vaterl
Proj[B_Name::=Name, Vater]
(Kaiser)
bekommen wir die Relation der Brüder - wobei hier
allerdings noch jeder, der einen Vater hat, als sein eigener
Bruder gilt, d. h. Tupel der Form
[A_Name='Ludwig I', B_Name='Ludwig I',
Vater='Karl I']
sind zugelassen.
Um diese auszuschließen, müssen wir anschließend eine
Selektion vornehmen:
Sel[A_Name ≠ B-Name]
Proj[A_Name::=Name, Vater] (Kaiser) Join[Vater]
Proj[B_Name::=Name, Vater] (Kaiser) )
10
Kommutativgesetz
Die Verbund-Operation ist kommutativ, d. h. es kommt nicht auf die Reihenfolge der Relationen an beide Relationen in einem Verbund sind vollständig gleichberechtigt.
Es gilt grundsätzlich
R Join[rs] S = S Join[rs] R
Assoziativgesetz
Die Verbund-Operation ist assoziativ, d. h. für drei Relationen R, S, T mit den entsprechenden Mengen
von Verbindungsattributen r s und s t gilt stets
(R Join[rs] S) Join[st] T = R Join[rs] (S Join[st] T )
Wir können somit vollständig auf die Angabe von Klammern verzichten und den letzteren Ausdruck
durch
R Join[rs] S Join[st] T
darstellen.
In der graphischen Darstellung auf Seite 91 bedeutet das, dass auch mehrere Relationen verknüpft
werden können und es nur auf die Existenz der Linien ankommt - nicht auf eine irgendwie geartete
Pfeilrichtung oder Nummerierung der Verbindungen.
Beispiel
Die Liste aller Artikel aus Lager 2, die von Kunden aus Kayhude
geordert wurden, bekommen wir durch
Proj[Artikel_Nr, Bezeichnung] (
Sel[Lagerplatz = 2 ∧ Ort = 'Kayhude'] (
Kunde
Join[Kunden_Nr]
Bestellung
Join[Bestell_Nr]
Position
Join[Artikel_Nr]
Artikel
)
)
oder
oder
Proj[Artikel_Nr, Bezeichnung] (
Sel[Ort = 'Kayhude'] (Kunde)
Join[Kunden_Nr]
Bestellung
Join[Bestell_Nr] Position
Join[Artikel_Nr]
Sel[Lagerplatz = 2] (Artikel)
Proj[Artikel_Nr, Bezeichnung]
Sel[Lagerplatz = 2]
Join[Artikel_Nr] Position
Join[Bestell_Nr]
Bestellung
Join[Kunden_Nr]
Sel[Ort = 'Kayhude'] (Kunde)
Alle drei Ausdrücke liefern dasselbe Ergebnis - allerdings ist der Rechenaufwand unterschiedlich. Am
höchsten ist er für die erste Formulierung, da hier erst alle Tupel verknüpft werden und die Selektion am
Schluss erfolgt. Für die 2. und 3. Formulierung ist a priori nicht klar, welche Formulierung weniger
Rechenaufwand erfordert - es ist dort nur die Reihenfolge der Verbund-Verknüpfung unterschiedlich möglicherweise ergibt sich daraus überhaupt kein Unterschied.
Dieses Beispiel zeigt auch, dass ein Datenbanksystem sinnvollerweise einen Abfrageoptimierer
benötigt. Dieser soll in der Lage sein, eine gegebene Abfrage in eine äquivalente Abfrage (d. h. eine
Abfrage mit derselben Ergebnismenge) so umzuformen, dass der Rechenaufwand möglichst gering
wird. Hierzu stehen dem Abfrageoptimierer Informationen über die physikalische Speicherorganisation
sowie über die Anzahl der Tupel in den beteiligten Relationen und gegebenenfalls Erfahrungen aus
vergangenen Abfragen zur Verfügung. Meistens sind die automatisch erzeugten Abfragepläne relativ
gut - bei komplexen Anfragen kann gegebenenfalls ein manuelles Tuning überlegen sein.
11
Beispiel
Im folgenden soll eine Liste der Bestellungen mit dem Bestelldatum, Lieferdatum und der
Kundennummer sowie dem Rechnungsbetrag ausgegeben werden.
Grp[Bestell_Nr, Bestelldatum, Lieferdatum, Kunden_Nr |
Rechnungsbetrag ::= SUM (Gesamtpreis * (l+ MWSt*0.01) ) ] (
Bestellung Join[Bestell_Nr] Position
Join[Artikel_Nr] Artikel
3.3.7 Das Kreuzprodukt
In der Datenbankpraxis spielt das Kreuzprodukt nur eine geringe Rolle - es ist aber im ursprünglichen
Coddschen Modell vor dem Verbund eingeführt worden, da das Kreuzprodukt mathematisch einfacher
ist als der Verbund. Der Verbund kann als Selektion auf dem Kreuzprodukt definiert werden.
Umgekehrt ist das Kreuzprodukt ein Spezialfall des natürlichen Verbundes: wenn nämlich die Menge
der Verbindungsattribute leer ist, d. h.
R x S = R Join[ ] S
Die Voraussetzung für das Kreuzprodukt ist also, dass die Attributbezeichner der beteiligten Relationen
jeweils verschieden sind - gegebenenfalls sind sie vorher umzubenennen.
Beispiel
Seien die beiden Relationen Werktag und Unterrichtsblock gegeben.
Werktag
Unterrichtsblock
12
Werktag X Unterrichtsblock
Diese Relation enthält für jeden Tag jeden Unterrichtsblock. Bei 5 Tagen und 6 Unterrichtsblöcken also
5 * 6 = 30 Tupel. Dieses sind genau die möglichen Kästchen auf einem Stundenplan für einen Schüler
oder Dozenten.
Wenn wir nur die Tupel jeweils durch ein Paar
aus den ersten beiden Anfangsbuchstaben des
Tages und der Nummer des Blockes
beschreiben, und für die beiden Ausgangsrelationen die horizontale bzw. vertikale
Achse nehmen, bekommen wir ein Rechteck,
das genau die Kombinationen der beiden
Ausgangsrelationen enthält, wie in folgender
abgewandelter Darstellung sichtbar wird:
Allgemeiner:
Rl und R2 seien Relationen; alle Attribut-Bezeichner von R1 und R2 seien verschieden. Die Relation
Rl × R2 enthält alle Attribut-Bezeichner von R1 und R2. Für jedes Tupel t1 ∈ Rl und jedes t2 ∈ R2 ist
t1+t2 ∈ Rl × R2. Insbesondere ist die Anzahl der Tupel von R1 × R2 das Produkt der Anzahlen der
Tupel von Rl und R2, d. h. die Zahl kann sehr groß werden.
Eine nicht erwünschte Rolle spielt das Produkt aus folgendem Grund: vergisst ein Benutzer, die
Verbindungsattribute anzugeben, erhält er statt einer Verbund-Operation das Produkt. Leider sind im
Standard SQL-89 die Verbund-Attribute im Zusammenhang mit den Selektionskriterien festzulegen, so
dass es leicht vergessen werden kann. In SQL-92 ist dies nicht mehr so problematisch, da hier der
Verbund als eigene Operation in der Abfrage-Anweisung auftritt.
Falls das Produkt einer Relation mit sich selber gebildet werden soll, sind vorher mindestens in einer der
beteiligten Relationen die Attribute umzubenennen.
3.3.8 Der äußere Verbund (Outer Join)
Der Nachteil des natürlichen Verbundes ist, dass nur solche Tupel aufgenommen werden, für die
explizit (mindestens) eine Verknüpfung existiert. Wenn wir in unserem Versandhandel-Beispiel aber
zum Beispiel eine Liste aller Kunden haben wollen, jeweils mit ihren Bestellungen verknüpft, so
bekommen wir für die Kunden, für die keine Bestellung eingetragen ist, keine Ausgabe. Dieses ist in der
folgenden Relation dargestellt.
13
Beispiel
Proj[Name,Bestell_Nr,Bestelldatum] (Kunde Join[Kunden_Nr] Bestellung)
Nicht alle Kunden erscheinen in dieser Auflistung,
sondern nur die, für die Bestellungen eingetragen
sind. Wenn wir dagegen alle Kunden in der
Aufstellung sehen wollen, müssen wir den äußeren
Verbund benutzen.
Es ist allerdings zu berücksichtigen, dass der äußere Verbund nur eingeführt werden kann, wenn ein
Konzept von Nullmarken (vgl. Kapitel 3.3.10) eingeführt ist. Einige Attribute haben dann keine Werte,
was durch sogenannte Nullmarken gekennzeichnet wird.
Für die Relationen, deren Tupel auf jedem Fall erscheinen sollen, werden Sternchen an den eckigen
Klammern nach dem Join-Operator angebracht. Somit gibt es drei verschiedene äußere Verbunde:
Join*[...], Join[...]* und Join*[...]*. Diese werden als Left Outer Join, Right Outer Join und Full Outer
Join bezeichnet. Häufig werden sie auch abgekürzt als Left Join, Right Join und Full Join bezeichnet der oben eingeführte Verbund wird dann als Inner Join bezeichnet.
Die obige Abfrage wird dann wie folgt dargestellt:
Proj [Name, Bestell_Nr, Datum] (Kunde Join*[Kunden_Nr] Bestellung)
Wenn der äußere Verbund mit dem natürlichen Verbund gemischt wird, dann kommt es gegebenenfalls
auf die Reihenfolge der Operationen an. Wir können hier also nicht so sorglos auf Klammern verzichten
wie bei dem natürlichen Verbund.
Beispiel
Um die Liste aller Artikel zusammen mit einer Liste aller Kunden zu bekommen, die diese Artikel
gekauft haben, können wir folgenden Verbund verwenden:
Artikel Join*[Artikel_Nr]
(Position Join[Bestell_Nr] Bestellung Join[Kunden_Nr] Kunde)
Wir stellen dabei zuerst den inneren Verbund zwischen Position, Bestellung und Kunde her. Damit
haben wir alle »gültigen« Positionen mit den uns interessierenden Daten. Der anschließende äußere
Verbund mit der Relation »Artikel« stellt sicher, dass alle Artikel in der Liste erscheinen.
Von diesem Verbund bilden wir die Projektion auf die interessierenden Attribute und erhalten:
Proj[Artikel_Nr, Bezeichnung, Lieferdatum, Kunden_Name::=Name] (
Artikel Join*[Artikel_Nr]
(Position Join[Bestell_Nr] Bestellung Join[Kunden_Nr] Kunde)
)
14
Die Klammerung
(Artikel Join*[Artikel_Nr] Position)
Join[Bestell_Nr] Bestellung
Join[Kunden_Nr] Kunde
würde für den Fall, dass irgendeine Position nicht zu einer Bestellung gehört (ungültige Bestellung in
Positions-Relation) oder dass eine ungültige Kundennummer in der Bestellungs-Relation enthalten ist,
die entsprechenden Artikel nicht mit aufführen, da für Artikel ohne Positionen das Verbindungsattribut
eine Nullmarke enthält.
Hinweis Wie wir eben gesehen haben, ist in der Praxis die Verwendung eines äußere Verbundes unter
der Verwendung von mehr als zwei Relationen problematisch. Es ist eine sehr genaue Analyse
Voraussetzung, da ein Assoziativgesetz (vgl. Seite 93) für äußere Verbunde nicht gilt.
3.3.9 Mengenoperationen
Seien R1 und R2 Relationen vom gleichen Typ (d.h. die Attribut-Bezeichner und ihre entsprechenden
Domänen sind gleich, vgl. Kap. 1.4.3). Dann sind durch
RI ∪ R2
für die Vereinigungsmenge der Tupel von RI und R2, d. h. die Menge der Tupel, die in Rl
oder in R2 oder in beiden Mengen enthalten sind,
Rl ∩ R2
für die Durchschnittsmenge, d. h. die Menge der Tupel, die sowohl in R1 und R2 enthalten
sind,
RI \ R2
für die Differenzmenge, d. h. die Menge der Tupel von R1, die nicht in R2 enthalten sind,
rein mengentheoretisch weitere Relationen definiert.
Beispiele
Sel[Lagerplatz=5] (Artikel) ∪ Sel[Lagerplatz=7] (Artikel)
Sel[Verpackung='Karton'] (Artikel) ∩ Sel[Lagerplatz=7] (Artikel)
Sel[Lagerplatz=7] (Artikel)
\ Sel[Verpackung='Karton'] (Artikel)
Diese Beispiele können auch jeweils durch eine einfache Selektion beschrieben werde
15
Sel[Lagerplatz=5
∨ Lagerplatz=7] (Artikel)
Sel[Verpackung = 'Karton^ Lagerplatz=7] (Artikel)
Sel[Lagerplatz=7 ∧ Verpackung ≠ 'Karton'] (Artikel)
Wenn dagegen zwei Relationen verknüpft werden sollen, die sich nicht von einer gemeinsamen
Oberrelation ableiten lassen, können die Mengenoperationen Vereinigung und Differenz nicht durch
andere Operationen ersetzt werden. Der Durchschnitt zweier Mengen kann allerdings als natürlicher
Verbund dargestellt werden, wobei alle Attribute als Verbindungsattribute zu nehmen sind, vgl. die
Relation im folgenden Beispiel 2.
So können wir durch Verknüpfung der Relation »Kunde« mit der Relation »Lieferant« u. a. folgende
Relationen bilden:
Beispiel 1
Proj[Name,Straße,PLZ,Ortl(Kunde) ∪ Proj[Name,Straße,PLZ,Ort] (Lieferant)
ist die Relation der Geschäftspartner.
Beispiel 2
Proj[Name,Straße,PLZ,Ortl(Kunde)
∩ Proj[Name,Straße,PLZ,Ortl (Lieferant)
ist die Relation der Lieferanten, die gleichzeitig Kunden sind. Dieses ist äquivalent zu
Proj[Name,Straße,PLZ,Ort] (Kunde)
Join[Name,Straße,PLZ,Ort]
Proj[Name,Straße,PLZ,Ort] (Lieferant)
Beispiel 3
Proj[Name,Straße,PLZ,Ort] (Kunde)
\ Proj[Name,Straße,PLZ,Ort] (Lieferant)
ist die Relation der Lieferanten, die keine Kunden sind.
3.3.10 Übungsaufgaben
Aufgabe 3.2
Beschreiben Sie folgende Fragen durch Verknüpfung der Relationen aus dem Anhang C.
a) An welchen (verschiedenen) Lagerplätzen haben Sie Artikel?
b) An welchen Orten mit PLZ wohnen Kunden?
c) Bei welchen Positionen sind Artikel mit den Nummern 'G001', 'G002' oder 'G003' geliefert worden?
d) Bei welchen dieser Positionen ist die Liefermenge größer als 2?
e) Bei welchen Positionen sind keine Artikel mit den oben genannten Nummern geliefert worden?
f) Welche Kunden sind keine Stammkunden? Geben Sie die Kundennummer, den Namen, den Ort und
den Status aus.
g) Welche Kunden sind keine Stammkunden und nicht aus Husum?
h) Welche Bestellungen sind vom Mai 1996 ?
i) Es sollen die Positionen aufgelistet werden, in denen die Artikel 'K001' oder 'G003' vorkommen.
j) Bei welchen Artikeln liegt der Listenpreis zwischen 6 und 15 DM?
16
k) Lassen Sie pro MWSt-Satz die Anzahl der davon betroffenen Artikel anzeigen.
1) Geben Sie jeweils die größte Kundennummer der Kunden mit demselben Status aus.
m) Zeigen Sie je Lagerplatz den kleinsten, den größten und den durchschnittlichen Listenpreis der dort
gelagerten Artikel an.
n) Wie viele Kunden haben Sie jeweils mit gleicher Postleitzahl?
o) Unter welcher Postleitzahl haben Sie mehr als einen Kunden?
p) Zu welcher Zahlungsart haben Sie mehr als zwei Kunden?
q) Zeigen Sie zu jedem Artikel den Mehrwertsteuersatz an.
r) Zeigen Sie mit Hilfe des Mehrwertsteuersatzes den Bruttopreis je Artikel an.
s) Zeigen Sie zu jeder Bestellung den Lieferort an.
t) Zeigen Sie zu jeder Bestellposition die Bestellmenge, Bestellnummer und den Lieferort an.
u) Zeigen Sie je Ort die Anzahl der bestellten Artikel an.
v) Ermitteln Sie den billigsten Artikel. (Nicht nur den Preis des billigsten Artikels!)
w) Welcher Kunde hat die letzte Bestellung aufgegeben? Zeigen Sie die Attribute kunden_nr, name und
bestell_nr an.
x) Welche Bestellungen sind nicht von Kunden aus Kayhude?
y) Welche Artikel haben einen höheren Listenpreis als alle Artikel aus Lager 2?
17
Die Datenbank
18
19
Herunterladen