Vorlesung MultimediaDatenbanksysteme Wintersemester 1999/2000 Wolfgang Kowarschick Fachhochschule Augsburg Draft (2. März 2000) 2 Inhalt 1 Einführung 7 1.1 Modelle, Fakten, Datenmodelle und Daten . . . . . . . . . . . . . 7 1.2 Historie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 1.3 Datenbankmodelle . . . . . . . . . . . . . . . . . . . . . . . . . 9 1.3.1 Extreme Ansätze für Datenbanksysteme . . . . . . . . . . 10 1.3.2 4GL-Datenbanksysteme . . . . . . . . . . . . . . . . . . 11 1.3.3 Besondere Aspekte von Datenbanken . . . . . . . . . . . 12 2 Entity-Relationship-Modelle 15 2.1 Entities . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15 2.2 Relationships . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16 2.2.1 2.3 Multiplizitäten . . . . . . . . . . . . . . . . . . . . . . . 17 Schlüssel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21 3 Das Relationenmodell 25 3.1 Grundkonzepte . . . . . . . . . . . . . . . . . . . . . . . . . . . 25 3.2 Überführung eines ER-Modells in ein relationales Schema . . . . 28 3.3 3.2.1 „Schema F“ . . . . . . . . . . . . . . . . . . . . . . . . . 28 3.2.2 Optimiertes „Schema F“ . . . . . . . . . . . . . . . . . . 30 Die Relationale Algebra und SQL . . . . . . . . . . . . . . . . . 33 3.3.1 Die Identität . . . . . . . . . . . . . . . . . . . . . . . . 35 3.3.2 Die Projektion . . . . . . . . . . . . . . . . . . . . . . . 36 3.3.3 Die Selektion . . . . . . . . . . . . . . . . . . . . . . . . 37 3.3.4 Vereinigung, Durchschnitt, Differenz . . . . . . . . . . . 38 3 Draft (2. März 2000) 3.4 3.5 3.3.5 Kartesisches Produkt und Join . . . . . . . . . . . . . . . 39 3.3.6 Division . . . . . . . . . . . . . . . . . . . . . . . . . . . 46 3.3.7 Subanfragen (Subqueries) . . . . . . . . . . . . . . . . . 50 Aggregation und Gruppierung . . . . . . . . . . . . . . . . . . . 55 3.4.1 Aggregation ohne Gruppierung . . . . . . . . . . . . . . 55 3.4.2 Aggregation mit Gruppierung . . . . . . . . . . . . . . . 56 Sortierung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57 3.5.1 3.6 3.7 Zusammenfassung . . . . . . . . . . . . . . . . . . . . . 58 Modifikation des Datenbestandes . . . . . . . . . . . . . . . . . . 58 3.6.1 Insert . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59 3.6.2 Delete . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59 3.6.3 Update . . . . . . . . . . . . . . . . . . . . . . . . . . . 60 3.6.4 Allgemeine Anmerkungen . . . . . . . . . . . . . . . . . 60 Views . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61 3.7.1 Das View-Update-Problem . . . . . . . . . . . . . . . . . 64 4 Oracle 67 4.1 SQLPlus . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67 4.2 Date . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68 5 Datenbankensysteme und Multimedia 71 5.1 Anforderungen an ein Multimedia-Datenbanksystem . . . . . . . 71 5.2 Relationale Datenbanksysteme und Multimedia . . . . . . . . . . 72 5.2.1 BLOBs . . . . . . . . . . . . . . . . . . . . . . . . . . . 73 5.2.2 CD-ROM-Datenbanken . . . . . . . . . . . . . . . . . . 74 5.2.3 RAID (Plattenfarmen) . . . . . . . . . . . . . . . . . . . 75 5.3 Volltextindexe (Inhaltssuche) . . . . . . . . . . . . . . . . . . . . 77 5.4 Hypermedia (navigierende Suche) . . . . . . . . . . . . . . . . . 86 5.4.1 5.5 Das Dexter-Referenz-Modell . . . . . . . . . . . . . . . . 90 Koppelung WWW 5.5.1 MMDBS . . . . . . . . . . . . . . . . . . 92 JDBC . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94 Draft (2. März 2000) 4 6 Objektorientierte Datenbanken 6.1 99 ODMG . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 99 6.1.1 Primitive Datentypen . . . . . . . . . . . . . . . . . . . . 101 6.1.2 Komplexe Datentypen . . . . . . . . . . . . . . . . . . . 101 6.1.3 ODL . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103 6.1.4 OQL . . . . . . . . . . . . . . . . . . . . . . . . . . . . 106 7 Normalformtheorie 7.1 7.2 7.3 Funktionale Abhängigkeit . . . . . . . . . . . . . . . . . . . . . 111 7.1.1 Reduzierte funktionale Abhängigkeiten . . . . . . . . . . 112 7.1.2 Schlüsselkandidaten . . . . . . . . . . . . . . . . . . . . 112 Normalformen . . . . . . . . . . . . . . . . . . . . . . . . . . . . 112 7.2.1 Erste Normalform (1NF) . . . . . . . . . . . . . . . . . . 112 7.2.2 Zweite Normalform (2NF) . . . . . . . . . . . . . . . . . 112 7.2.3 Dritte Normalform (3NF) . . . . . . . . . . . . . . . . . 113 7.2.4 Boyce-Codd-Normalform (BCNF) . . . . . . . . . . . . . 114 Zerlegung (Dekomposition) eines Relationenschemas . . . . . . . 114 7.3.1 7.4 111 weitere Normalformen . . . . . . . . . . . . . . . . . . . 117 Normalformen und ER-Modellierung . . . . . . . . . . . . . . . 118 A Literatur 121 A.1 Datenbanken . . . . . . . . . . . . . . . . . . . . . . . . . . . . 121 A.2 Objektorientierung . . . . . . . . . . . . . . . . . . . . . . . . . 121 5 Draft (2. März 2000) Draft (2. März 2000) 6 Kapitel 1 Einführung ✎ 1.1 Modelle, Fakten, Datenmodelle und Daten Der Mensch kann die Welt/Realität nicht direkt erfassen. Er bildet letztlich immer (zumindest auf geistiger Ebene) Modelle der Realität. Neue Erkenntnisse kann er nur gewinnen, wenn er neue Fakten in seine Modellwelt einordnen oder die Modellwelt geeignet abändern kann. Realitätsausschnitte Modelle Fakten Musik Notensystem Eine kleine Nachtmusik Thermodynamik Differentialgleichungen , Chemie Formeln Meereswellen Chaostheorie Simulationen Städte, Länder etc. Landkarten Augsburger Stadtplan Mathematik und Informatik bilden ebenfalls abstrakte Modelle für die „Realität“, allerdings wesentlich formaler als dies mit natürlichen Sprachen möglich ist. Fakten werden in der Informatik normalerweise in Form von sogenannten Daten, d. h. als Zeichenketten modelliert. Multimedia-Daten (Audio, Video, Bilder etc.) werden von Datenbanksystemen meist lediglich als sogenannte BLOBs (Binary Large OBjects), d. h. als lange Folge von Bits dargestellt, deren Bedeutung einem DB-System unbekannt sind. Für gegebene Realitätsausschnitte können, um die Bedeutung von Fakten festzulegen, sogenannte Datenmodelle entwickelt werden (siehe beispielsweise die bereits bekannte „objektorientierte Modellierung“). Die Abbildung eines Realitätsausschnittes auf Fakten eines Modells oder – spezieller – auf Daten eines Datenmodells stellt immer einen sogenannten Abstraktionsschritt dar. Abstraktion ermöglicht einerseits ein besseres Verständnis, bedeutet andererseits aber einen Präzisionsverlust, d. h., (hoffentlich) 7 Draft (2. März 2000) unwesentliche Teile der Realität werden vernachlässigt.1 Datenmodelle sind normalerweise nicht sehr umfangreich, die zugehörigen Datenbestände können dagegen häufig beliebig groß werden. Die Aufgabe von Datenbankmanagementsystemen (DBMS) ist es, große, langlebige Datenbestände effizient zu verwalten. Unter einem Datenbanksystem (DBS) verstehe ich ein Datenbankmanagementsystem (die eigentliche DB-Software) zusammen mit den zugehörigen Datenmodellen, Datenbeständen und weitere Komponenten (wie grafische Benutzerschnittstelle, Report Generator, WWW-Schnittstelle etc.). Mit Datenbanksystemen werden wir uns in dieser Vorlesung befassen. Beispiele – Banken (Die Datenbankpioniere) – Deutsche Bahn AG – Bibliotheken (Library of Congress (LoC), viele multimediale Daten) – Metreologische Institute – NASA/ESA (Satelliten, Marssonde etc.) – Versandhandel (Kataloge) – etc. Datenbestände der DB AG – Fahrpläne – Tarife – Streckennetz – Wagenpark – Stromnetz – Personal – etc. Frage: Wie sieht beispielsweise ein Datenmodell für Fahrpläne aus? kurze Antwort: Fahrpläne werden normalerweise als Tabellen realisiert. Das Datenmodell legt die Strukturen dieser Tabellen sowie die erlaubten Inhalte der einzelnen Zeilen und Spalten fest. 1 Der Präzisionsverlust ist manchmal allerdings erheblich. Man denke nur an die zahllosen Interpretationsmöglichkeiten eines einzelnen Musikstückes wie der kleinen Nachtmusik. Draft (2. März 2000) 8 Datenbestände Bibliotheken – Texte, Bilder, Tonträger, Videos (z. B. LoC: Originalwalzen für Edison-Phonographen, Orginalfilme von Laurel/Hardy etc.) – Kataloge – Benutzerverwaltung – Bestellwesen – etc. Geo-Informationssysteme Ein Spezialgebiet der DB-Welt stellen die sogenannten Geo-Informationssysteme (GIS) dar. In derartigen Systemen geht es darum, 2- und 3-dimensionale Landkarten zu verwalten. Die Kostenrelation eines typischen GIS-Systems sieht ungefähr wie folgt aus: Kosten Hardware: Faktor 1 Kosten Software: Faktor 10 Kosten Datenerfassung: Faktor 100 1.2 Historie Die historische Entwicklung von Datenbanksystemen: 1. Hierarchische DBS (IMS von IBM) 2. Netzwerk-DBS (CODASYL; UDS von Siemens) 3. Relationale DBS (System R von IBM) 4. Objektorientierte DBSe (überspitzt formuliert: Rückschritt zu 2.) Vor- und Nachteile von RDBS (Schemamodifikation ohne Effizienzeinmußen möglich) und OODBS (sehr effizient für Spezialanfragen – genauso wie Netzwerk-DBS – wenig effizient für „nicht-schema-konforme“ Anfragen). 1.3 Datenbankmodelle Datenmodelle für Datenbanken sollen folgende Eigenschaften haben: 1. verständlich, insbesondere nicht zu umfangreich 9 Draft (2. März 2000) 2. ausreichend präzise und ausreichend vollständig für bestimmte Zwecke 3. effizient realisierbar, d. h., eine gewünschte Auskunft kann bzgl. eines zugehörigen Datenbestandes „schnell“ erteilt werden 4. leicht modifizierbar, um schnell an neue Gegebenheiten angepasst werden zu können ohne dass vorhandene Datenbestände wertlos werden Lösungen: ad 1. einheitliche Formalisierungsmethode mit wenigen formalen Elementen ad 2. möglichst mächtige Formalisierungsmethode ad 3. kleiner, aber mächtiger Satz von effizient zu realisierenden Elementaroperationen 1970 kam Codd auf die Idee, mathematische Relationen (d. h. Tabellen) und relationale Operationen (Vereinigung, Durchschnitt, Differenz, kartesisches Produkt (Join)) zur Verwaltung von Massendaten einzusetzen. Es hat sich im Lauf von bald 30 Jahren gezeigt, dass dieser Formalismus, so einfach er auch ist, sehr wohl geeignet ist, hochkomplexe Datenmodelle zu erstellen und die zugehörigen Daten effizient zu verwalten. Das Relationenkalkül hat allerdings auch einige Schwächen. Und so verwundert es nicht, dass im Laufe der letzten 30 Jahre auch andere Formalismen entwickelt wurden, allen voran die objektorientierten Systeme. Verdrängen werden sie die relationalen Systeme allerdings nicht so schnell – es zeichnet sich vielmehr ab, dass in Zukunft Mischungen aus beiden Welten, die sogenannten objektrelationalen Systeme eine immer größere Bedeutung erlangen werden. ✎ ✎ ✎ !"#$% &' (*)$ &)$+)-,*/.102)* 3 4$57698:6<;= ?> 1.3.1 Extreme Ansätze für Datenbanksysteme Natürlichsprachliche Datenbanksysteme Die an leichtesten zu handhabenden Datenbanksysteme wären diejenigen, die direkt natürlichsprachliche Beschreibungen (= Datenmodelle) und Fakten verarbeiten könnten (siehe Bordcomputer von Raumschiff Enterprise). Darstellung: Text @ Draft (2. März 2000) Bilder, Töne ABABA 10 Auskünfte: Information Retrieval (z. B. OMNIS, WAIS, LEXIS) Änderungen: Text-/Bild-/Audio-/ ABACA Editoren Vorteile: einfach handzuhaben, mächtig Nachteile: derzeit leider nur ansatzweise realisierbar, da volles Sprachverständnis implementiert werden müsste 3GL-Datenbanksysteme Wenn natürlichsprachliche Ansätze nicht funktionieren, warum dann nicht einfach vorhandene algorithmische Sprachen (C++, Java, Pascal ABABA ), d. h. Sprachen der dritten Generation (3GL2 ) einsetzen? Darstellung: direkte Nachbildung von z. B. Papierformularen durch Listen, Bäume, Geflechte etc. Auskünfte: Spezialprogramme Änderungen: Spezialprogramme Vorteile: gewohnte Repräsentation und Verarbeitung Beispiel: (mechanisches Pferd) Nachteile: aufwendig, starr, Mehrbenutzerbetrieb schwierig Beispiele: frühe Flug- und Banksysteme 1.3.2 4GL-Datenbanksysteme Für heutige Datenbanken wurden Sprachen und Formalismen oberhalb von 3GLSprachen aber natürlich unterhalb natürlichsprachlicher Systeme entwickelt. relationale Systeme Darstellung: Relationen (Tabellen) + Integritätsbedingungen (Invarianten), um fehlerhafte Datenbankinhalte zu vermeiden Auskünfte: deklarative (nicht-algorithmische), d. h. beschreibende Sprache: relationale Algebra (SQL: select ACABA from ABABA where) Änderungen: Satz von Modifikationsoperationen (SQL: insert, delete, update) unter Beachtung von Integritätsbedingungen Vorteile: 2 einfach handzuhaben, effizient (mittels Hilfsdatenstrukturen wie BBäume (R. Bayer), R-Bäume etc.), weit verbreitet 1GL = Hardware-Codierung, 2GL = Assemblersprachen 11 Draft (2. März 2000) Nachteile: nicht turingmächtig, d. h., es gibt Probleme, die zwar mit algorithmischen Sprachen, nicht jedoch mit gängigen relationalen Systemen gelöst werden können. Leider sind diese Probleme nicht nur theoretischer, sondern durchaus praktischer Natur. Beispiel: Wegsuche in großen Netzwerken wie Bahnnetz, Stromnetz, Internet etc. Workaround: Einbettung von relationalen (4GL)-Sprachen in algorithmische (3GL)-Sprachen D impedance missmatch objektorientierte Systeme Darstellung: Klassen und Objekte Auskünfte: Methoden Änderungen: Methoden Vorteile: Nachteile: ✎ ✎ verständlich und benutzerfreundlich, turingmächtig kein mathematischer Formalismus (nur Ansätze) D Effizienz leidet wegen fehlender Optimierungstechniken; sehr jung und daher unausgereift im Vergleich zu relationalen Systemen; Integritätsbedingungen werden nur sehr rudimentär unterstützt "! #$% &E> ?F 1.3.3 Besondere Aspekte von Datenbanken Im Vergleich zu typischen 3GL-Anwendungen weisen Datenbanken einige Besonderheiten auf: Lebensdauer Die Daten leben wesentlich länger als einzelne Programmausführungen. In 3GLSprachen kann dies allerdings mittels Dateien realisiert werden, in denen die Daten zwischen zwei Programmausführungen abgelegt werden. Öffentlichkeit und Qualität Die Daten werden von (vielen) verschiedenen Programmen verschiedener Programmautoren bearbeitet D Qualität und Richtigkeit der Daten sind fraglich. Fehler verseuchen daher langsam eine Datenbank und leben lange rotten“. Draft (2. März 2000) 12 D DBs „ver- Beispiel aus der Praxis: Bibliotheksbestandsdaten mit Erfassungsjahren 98, 97, 97 ABABA sowie 1998, 1997, 1996 ACABA abhängig vom Erfasser D Sortierung nach Erfassungsdatum schlägt fehl. Abhilfe: geeignete Schutzmaßnahmen – Integritätsüberwachung – Zurücksetzen auf fehlerfreien Zustand im Fehlerfall (Abort, Recovery) – Benutzerverwaltung und Zugriffsschutz – Teamwork, Groupwork, CSCW (computer supported cooperative work) Dies alles wird von 3GL-Sprachen nicht unterstützt. Simultanbearbeitung Dieselben Daten werden gleichzeitig (parallel auf Mehr- oder pseudoparallel auf Einprozessorrechnern) von mehreren Programmen bearbeitet. D Synchronisation des Ablaufs durch das Datenbanksystem. Dies wird von 3GL-Sprachen auch nicht unterstützt. In diesem Zusammenhang ist der Begriff der Serialisierbarkeit von Bedeutung: Eine Ablaufsteuerung heißt serialisierbar (seriell, konsistent), wenn es für jede Menge GIHCJBABABABJ&GK von parallellaufenden Transaktionen (= elementare Arbeitsschritte eines Datenbanksystems) mindestens eine serielle (lineare) Anordnung dieser Transaktionen gibt, sodass die Nacheinanderausführung der einzelnen Transaktionen in dieser Reihenfolge dasselbe Ergebnis liefert wie die parallele Ausführung. LMM z. B. RBS GIH S G N GPO TVU G XW GPQ W GIH W GYO GPQ Gegenbeispiel Prozess A: lese a; a:=a+1, schreibe a; Prozess B: lese a; a:=a*2, schreibe a; a:=5; A; B; D a=12 a:=5; B; A; D a=11 a:=5; B||A; (A und B laufen parallel) D a=12 oder a=11 oder a=6 oder a=10 13 Draft (2. März 2000) ein möglicher paralleler Ablauf Prozess A lese a (=5) Prozess B lese a (=5) a := a+1 (=6) a := a*2 (=10) schreibe a (=10) (über)schreibe a (=6) Eine serielle Ablaufsteuerung verhindert derartige Fehler (a=6 oder a=10). Draft (2. März 2000) 14 Kapitel 2 Entity-Relationship-Modelle Ursprung: [Chen, 1976] 2.1 Entities Das Entity-Relationship-Modell (ER-Modell) kann als Vorläufer der modernen objektorientierten Modelle, wie z. B. OMT oder UML, angesehen werden. Objekte werden im ER-Modell Entities genannt. Entities haben Attribute, den Methodenbegriff gibt es allerdings (zumindest im ursprünglichen ER-Modell) von Chen [1976] nicht. Eine Menge von Entities mit denselben Attributen (aber i. Allg. unterschiedlichen Attributwerten) heißt Entity-Menge (entity set). Entity-Mengen entsprechen den Klassenextensionen in objektorientierten Systemen. Einen Entitynamen zusammen mit den zugehörigen Attributnamen und -typen bezeichnet man als Entitytyp. Entitytypen entsprechen Klassendefinitionen in objektorientierten Systemen. Heute werden meist sogenannte EER-Modelle (Extended ER) eingesetzt. Diese haben viele Aspekte der objektorientierten Modellierung übernommen. Im weiteren subsummiere ich unter dem Begriff ER alle gängigen ER-Varianten d. h. auch EER-Modelle. Ein wesentlicher Unterschied zu objektorientierten Modellierungstechniken ist jedoch, dass Entities normalerweise keine OIDs im objektorientierten Sinne zugeordnet sind. Anstelle dessen werden sogenannte Schlüsselattribute gekennzeichnet, deren Werte eine Entity eindeutig identifizieren. Ein typisches Schlüsselattribut ist Personalnummer. In ER-Modellen ist der Designer also selbst verantwortlich für die Vergabe von Identifikatoren. Ein anderer Unterschied zu objektorientierten Modellen ist, dass in ER-Modellen meist direkt mit Attributen gearbeitet wird. Methoden werden normalerweise nicht unterstützt. 15 Draft (2. März 2000) 2.2 Relationships Zwischen Entitymengen können Beziehungen (Relationships) bestehen. In OMT heißen Beziehungen Assoziationen. Beziehungen können ebenso wie Entitytypen eigene Attribute besitzen. Beispiele Entitymenge Beziehung Person besitzt Entitymenge Auto Name Kennzeichen Erstzulassung:Datum Mann is a Person Auto has a Motor Motor is part of Auto UML-Notation Person Auto Name Kennzeichen besitzt Erstzusassung: Datum Mann Person Auto Motor Draft (2. März 2000) 16 2.2.1 Multiplizitäten Genauso wie in UML kann man die Multiplizität (Vielfachheit) einer Beziehung genauer festlegen. Man beachte, dass die im Folgenden vorgestellte graphische Notation nur beispielhaft ist. Jedes ER-Modellierungswerkzeug verwendet seine eigene Symbolik. 1:1-Beziehungen Jeder Angestellte hat genau eine Personalakte. Umgekehrt gehört jede Personalakte zu genau einem Angestellten. Angestellter 1 hat Angestellter 1 1 Personalakte 1 Personalakte UML 1:n-Beziehungen und n:1-Beziehungen Jeder Angestellte arbeitet für genau eine Firma, jede Firma hat beliebig viele Angestellte Angestellter n arbeitet für Angestellter 0..* 1 Firma 1 Firma UML m:n-Beziehungen Jede Person kann von beliebig vielen Firmen Aktien besitzen, und jede Firma kann beliebig viele Aktionäre haben. Person m Person 0..* arbeitet für 17 n Firma 0..* Firma UML Draft (2. März 2000) Weitere Beziehungen Wie wir bereits von UML kennen, kann man Multiplizitäten noch wesentlich genauer beschreiben: Optionalität: Jede Frau hat höchstens einen (Ehe-)Mann und umgekehrt. Mengenbeschränkungen: Ein PKW hat 3 (Schumi!) bis 10 Räder Et cetera Diese Beziehungen können auch in ER-Diagrammen ausgedrückt werden: Frau 0-1 PKW 1 Ehegatte 0-1 Mann hat 3-10 Räder Bei der Überführung eines ER-Modells oder eines UML-Modells in ein relationales Datenbankschema ist allerdings die (grobe) Unterscheidung von 1:1-, 1:n und m:n-Beziehungen zunächst meist ausreichend. Eine genauere Spezifikation der Multiplizitäten wird erst in einem zweiten Schritt benötigt, und zwar bei der Formulierung von Integritätsbedingungen, die das Datenbanksystem automatisch überwachen soll. ✎ ✎ "! #$% &EF [Z Anmerkung Die hier vorgestellte Art der Notation von Multiplizitäten hat (sowohl in ER-Diagrammen als auch in UML-Diagrammen) einen gravierenden Nachteil: Sie ist nur für Zweierbeziehungen, nicht jedoch für Dreier-, Vierer-, Fünfer- ABABA Beziehungen geeignet. Der Grund dafür ist, das die Multiplizitäten immer bei gegenüberliegenden Entitymengen notiert werden. n Firma Angestellte Dieses Diagramm liest man wie folgt: Die Firma beschäftigt beliebig viele Angestellte. Das funktioniert bei Mehrfachbeziehungen nicht mehr. Wie sehen hier die Multiplizitäten aus? Draft (2. März 2000) 18 1:1 1:n n:1 n:m A B a1 a2 a3 a4 a5 b1 b2 b3 b4 b5 a1 a2 a3 a4 a5 b1 b2 b3 b4 b5 a1 a2 a3 a4 a5 b1 b2 b3 b4 b5 a1 a2 a3 a4 a5 b1 b2 b3 b4 b5 Abbildung 2.1: Veranschaulichung der Standardbeziehungen 19 Draft (2. März 2000) hört Vorlesung Student Hochschule Professor Es gibt daher Modellierungstechniken (wie z. B. die Informationsanalyse von Prof. Kern-Bausch), die die Multiplizitäten genau anders herum platzieren. Firma 1-n beschäftigt 0-1 Person Dieses Diagramm liest man wie folgt: Eine Firma beschäftigt 1 bis n Personen, d. h. beliebig viele Personen, und jede Person ist bei einer oder keiner, d. h. bei höchstens einer Firma beschäftigt. Das obige Diagramm kann nun wie folgt notiert werden: Student 0-n hört Vorlesung 1-n Hochschule 0-5 Professor Ein Student hört beliebig viele Vorlesungen, eine Hochschule bietet viele Vorlesungen an, ein Professor hält bis zu 5 Vorlesungen. Bei Modellierungstechniken wie UML, die mit Mehrfachbeziehungen nicht gut umgehen können, sollte man jede Mehrfachbeziehung durch eine neue EntityMenge (Klasse) und mehrere Zweifachbeziehungen zu ersetzen. Draft (2. März 2000) 20 Student n hört n Vorlesung n 1 bietet an Hochschule 0-5 liest 1 Professor Dieses Diagramm enthält mehr Information als das vorherige. Dennoch könnte es noch weitere Einschränkungen geben, die nicht direkt im Diagramm dargestellt werden können, wie z. B. „Studenten dürfen Vorlesungen nicht an mehreren Hochschulen belegen“. Derartige Bedingungen werden normalerweise einfach textuell in das Diagramm eingefügt und später als Integritätsbedingung formuliert. Anmerkung 2 Entitymengen bzw. Klassen werden meist durch Substantive beschrieben, Beziehungen dagegen durch Verben (Person besitzt Auto). Leider ist diese Faustregel nicht allgemeingültig, wie man schon am Beispiel „hört Vorlesung“ gesehen hat. Weitere Beispiele: Prüfungen vs. prüft, Vorgang vs. bearbeitet Wir werden im Folgenden noch sehen, dass in relationalen Datenbanken der Unterschied zwischen Entities und Relationships völlig verschwindet: Beides wird durch Tabellen dargestellt. Anmerkung 3 In dieser Vorlesung wird im Weiteren nur noch die bereits bekannte UML-Notation verwendet, auch wenn von Entities und Relationships die Rede ist. Es wird vorausgesetzt, dass die Grundprinzipien der objektorientierten Modellierung bekannt sind (Vorlesung MMProg) und dass der Unterschied ER UML (ER: keine Methoden, keine OIDs) klar ist. 2.3 Schlüssel Eine Entitymenge ist im wesentlichen eine Menge von Tupeln: {(Name: "Wolfgang", Geb: 1961, Tel: 325), (Name: "Anna", Geb: 1961, Tel: 377), (Name: "Hans", Geb: 1964, Tel: 235) } 21 Draft (2. März 2000) Da es sich um eine Menge handelt, kann es jedes Tupel höchstens einmal geben. In unserem Betrieb gibt es also keine zwei Wolfgangs, die 1961 geboren und die Telefonnummern 325 haben. In einer Entitymenge bilden alle Attribute zusammen immer einen Identifikator für das Tupel, den sogenannten trivialen Schlüssel. Allerdings kann es in einem Betrieb mit vielen 1000 Mitarbeitern schon mal passieren, dass zwei Mitarbeiter den gleichen Namen und das gleiche Geburtsdatum haben. Wenn dann auch noch beide im gleichen Zimmer mit nur einem Telefon sitzen, kann man diesen Sachverhalt in der Datenbank nicht mehr darstellen. Dieses Problem lösen die Unternehmen mit einer Personalnummer, d. h. mit einem weiteren Attribut, welches für jeden Mitarbeiter eindeutig ist. Die Personalnummer entspricht einem OID in OO Systemen. {(PN: 007, Name: "Wolfgang", Geb: 1961, Tel: 325), (PN: 008, Name: "Wolfgang", Geb: 1961, Tel: 325), ABACA } In diesem Fall bildet bereits das Attribut PN alleine schon einen Schlüssel. Für jede Tabelle wird normalerweise ein sogenannter Primärschlüssel definiert. In ERDiagrammen werden die Primär-Schlüsselattribute meist durch Unterstreichung markiert. Attribute, deren Wert nicht unbedingt ausgegeben werden muss (die also den Wert NULL annehmen können), werden mit einem Stern * markiert. Schlüsselattribute können nie den NULL-Wert annehmen, werden also nie mit * markiert. Person PN Name Geb Tel* Im Zusammenhang mit Schlüsseln gibt es viele Fragen: 1. Welche Attributkombinationen kommen als Schlüssel in Frage? 2. Welche der Schlüssel sind minimal (d. h., man kann kein Attribut weglassen, ohne die Schlüsseleigenschaft zu zerstören)? Minimale Schlüssel heißen Schlüsselkandidaten (candidate keys). 3. Welcher der Schlüsselkandidaten soll als Primärschlüssel verwendet werden? Jedes Datenbanksystem kann den Zugriff auf Primärschlüssel-Attribute besonders effizient gestalten, da es für diese Attribute immer einen sogenannten Primärindex anlegt. Draft (2. März 2000) 22 4. Ist ein Schlüsselkandidat wirklich für jeden nur denkbaren Datenbankzustand ein Schlüssel? (Oft denkt ein DB-Designer nicht daran, dass es auch in einem 5-Mann-Betrieb zwei „Sepp Maier“ geben kann und so die Attribute Nachname und Vorname gar keinen Schlüsselkandidaten bilden.) 5. Ist ein Schlüssel eindeutig bzgl. einer Entitymenge oder bzgl. der ganzen Datenbank? (OIDs sind bzgl. einer oder gar mehrerer Datenbanken eindeutig.) 6. Sind Schlüssel wiederverwendbar (Personalnummern, Matrikelnummern, Autonummern)? Anmerkung Man kann auch den lesenden Zugriff auf andere Schlüsselkandidaten und Nichtschlüsselattribute effizienter gestalten, indem man für derartige Attribute sogenannte Sekundärindexe definiert. Allerdings hat die Einführung von vielen Sekundärschlüsseln einen deutlichen Effizienzverlust der Modifikationsoperationen (Einfügen, Ändern, Löschen) zur Folge. \^]_<_)-,$`#*a4I]_3 ]b_`c"4d ]_3#[efhgij3kml$oni#Epqbrq#$l$3n #*istb`rqvuwyxz4dbz4|{ Beispiel Entity-Menge Prüfung: Professor, Student, Fach, Datum, Uhrzeit, Raum, Note Schlüsselkandidaten: Student, Fach, Datum Student, Professor, Datum, Uhrzeit Entity-Menge Adresse: Straße, Hausnummer, PLZ, Ort Schlüsselkandidat: Straße, Hausnummer, PLZ Der Ort ist bekannt, wenn die PLZ bekannt ist (PLZ } Ort). Man spricht hier von einer sogenannten funktionalen Abhängigkeit.1 Schlüsselkandidaten für Adressen in den USA: City Street ZIP In manchen Staaten gilt:2 City Street Außerdem gelte: ZIP } CITY. 1 2 } ZIP. Anmerkung von Michael Schulze: Diese funktionale Abhängigkeit gilt in Deutschland nicht. Es gibt mehrere Orte mit gemeinsamer PLZ. Anmerkung von Claus Tews: Diese Abhängigkeit gilt i. Allg. auch nicht. Es gibt verschiedene Orte (z. B. Berlin) mit gleichen Straßennamen (z. B. Unter den Linden). Ob es amerikanische Staaten gibt, in denen diese Abhängigkeiten wirklich gelten, ist unbekannt. 23 Draft (2. März 2000) ✎ Unter disen Voraussetzungen gibt es zwei Schlüsselkandidaten: City Street ZIP Street ✎ ✎ ✎ "! #$% &`Z bE~ pC4I#$"4db.<]_b 4dy,*3 *3 Draft (2. März 2000) 24 Kapitel 3 Das Relationenmodell 3.1 Grundkonzepte Das Relationenmodell (RM) von Codd kann (im Gegensatz zu den meisten OOModellen) mathematisch exakt definiert werden. Hier sollen allerdings nur die wesentlichen Grundideen vorgestellt werden. 1. Domänen Eine Domäne ist eine Menge von Werten. Typische Domänen sind Integer, String (Varchar), Bool, Float etc., Integer* (= Integer Null ), String* (= String Null ) etc. In SQL enthält jeder Elementary defaultmäßig den Nullwert Null. Braucht man diesen nicht, so muss man dies explizit angeben: Integer NOT NULL etc. 2. Relationen 6 6 Eine Teilmenge 7H ABABA K eines kartesischen Produktes1 von Domänen heißt Relation. Relationen kann man sich als Tabellen vorstellen in deren -ter Spalte nur Elemente der Domäne enthalten sind: Beispiel 6 Person String Integer Wolfgang 37 Marianne 36 Sibylle 11 . . . 3. Tupel Ein Element einer Relation heißt Tupel. Tupel stellen also die Zeilen der Tabellen dar. 1 Zur Erinnerung: Das kartesische Produkt von mehreren Mengen ist die Menge aller Tupel, die sich aus diesen Mengen bilden lassen: |PCdaPB ¥ C¥d ¡IzIIP¢ ¡IzP1 ¡z£¢ II£ ¡&II£1 ¡I¤PB£ ¡¤P11 ¡ `Bd ¡IIP¢ &¦¦P¦jBI& ¡I¤1 ¡¦P¦P¦j§BI& ¡I¤§1 ¡¦P¦¦y&¦¦&¦¡¢¦ 25 Draft (2. März 2000) 4. Attribut Die „Spalten“ einer Relation heißen Attribute. Sie erhalten eindeutige (und sinnvolle) Namen. 5. Relationenschema Ein Relationenschema besteht aus einem Relationnamen gefolgt von einer Liste von Attributen mit zugeordneten Domänen: ©¨£ªwH «¬HXJCABABA¢JIª­K®«Kt¯ 6. (Relationales) Datenbankschema Eine Menge von Relationenschemata heißt Datenbankschema 7. (Relationale) Datenbank Ein Datenbankschema (Datenmodell) zusammen mit einer Menge von zugehörigen Relationen (Fakten) heißt (relationale) Datenbank (RDB). Anmerkungen 1. Objektorientierte Datenbanken werden ebenso wie RDBen über Datenmodelle und Fakten definiert: Datenmodelle: Klassendefinitionen (+ Methodenimplementierungen) Fakten: Klassenextensionen 2. Relationen sind Mengen im mathematischen Sinn: D a) es gibt keine Duplikattupel b) die Reihenfolge der Tupel ist irrelevant Achtung: Implementierungen von RDBS realisieren Mengen meist als Listen (mit Duplikaten und Reihenfolge) oder als Multimengen (mit Duplikaten ohne Reihenfolge). 3. In der obigen Definition von Relationenschema ist die Reihenfolge der Spalten wesentlich. Eigentlich ist dies jedoch unwichtig, da die Spalten eindeutig benannt werden. Daher werden wir in Zukunft unser Augenmerk mehr auf die Namen der Spalten als auf deren Reihenfolge richten. 4. Die Struktur einer Datenbank, d. h., das Datenbankschema wird durch sogenannte DDL-Anweisungen (Data Definition Language, create table, alter table, drop table etc.) festgelegt. 5. Der Inhalt einer Relation (die Fakten) wird durch sogenannte DML-Anweisungen (Data Manipulation Language, select, insert, modify, delete) abgefragt und modifiziert. Das Datenbankschema selbst wird meist auch in (leider nicht genormten) Tabellen abgelegt und kann daher mit DML-Befehlen (select) gelesen werden. Die Manipulation der Systemtabellen erfolgt dagegen immer mit DDL-Befehlen. Draft (2. März 2000) 26 6. Für RDBS gibt es meist eine wesentliche Einschränkung. Als Attributdomänen dürfen keine komplexe Datentypen wie Liste, Menge, Feld oder Tupel (Record) verwendet werden, sondern nur primitive Datentypen wie Integer, Float, Bool und String2 Anstelle der Tabelle: Name Hobbies Wolfgang {Akkordeon,Fahrrad,Flöte} Sonja {Flöte,Ballett} muss man die Tabelle Name Wolfgang Wolfgang Wolfgang Sonja Sonja Hobby Akkordeon Fahrrad Flöte Flöte Ballett erzeugen. Eine Relation ohne komplexe Attribute heißt Relation in erster Normalform (1NF). Leider kann man nicht jede NFNF-Relation (Non-First-Normal-Form) verlustfrei in eine 1NF-Relation überführen. Wenn es in der obigen Relation eine zweite Person Wolfgang mit anderen Hobbies ({Fahrrad,Judo}) gäbe, könnten beide nach der Normalisierung nicht mehr unterschieden werden. Hier müsste wieder ein zusätzlicher (künstlicher) Identifikator eingeführt werden. ID 1 1 1 2 2 3 3 Name Wolfgang Wolfgang Wolfgang Wolfgang Wolfgang Sonja Sonja Hobby Akkordeon Fahrrad Flöte Fahrrad Judo Flöte Ballett Objektorientierte Schemata sind i. Allg. nicht in 1NF. Es gibt aber auch RDBS, die NFNF-Relationen unterstützen. Man braucht dann allerdings weitere relationale Operatoren wie FOLD und UNFOLD zum Transformieren von NFNF-Relationen in 1NF-Relationen und umgekehrt. !"#$% &E~ 2 ✎ String wird in vielen Sprachen wie C++ als komplexer Datentyp (Array) behandelt! 27 Draft (2. März 2000) ✎ ?° 3.2 Überführung eines ER-Modells in ein relationales Schema ER-Modelle sind wesentlich ausdruckskräftiger als Relationenschemata, da zwischen Entities und Beziehungen unterschieden wird. Daher sollte man immer zunächst ein ER-Modell erstellen und dieses dann nach „Schema F“ in ein Relationenschema transformieren. 3.2.1 „Schema F“ 1. Jeder Entitytyp ± mit Attributen ª H JBABABABJª K und den zugehörigen Domänen H JBABABACJ1 K wird auf das Relationenschema ±¨£ª H «² H JBABACA1JIª K «² K ¯ abgebildet. 2. ISA-Beziehungen ³ isa ± können entweder durch Hinzunahme aller Attribute oder nur der Primärschlüsselattribute von ± zu ³ realisiert werden. Im ersten Fall hat man zwar mehr Daten als im zweiten, man spart sich aber später eine Joinoperation um in ³ auch an die von ± geerbten Nichtschlüsselattribute zu gelangen. Eine dritte Realisierungsmöglichkeit ist es, für eine gesamte ISA-Hierarchie nur eine einzige Tabelle zu definieren. Diese enthält die Attribute der Basisklasse sowie aller Subklassen. Nichtdefinierte Attributwerte werden mit Null initialisiert. 3. Ein Relationship zwischen Entity-Typen ± H JBABABABJ¢± K wird durch ein Relationenschema ©¨ACABA¯ dargestellt, das aus allen Primärschlüsselattributen aller Entitytypen ± H JBABABA¢J1± K besteht. Gleiche Attributnamen werden dabei geeignet umbenannt. Eigene Attribute der Relationship werden zum Relationenschema hinzugenommen. Draft (2. März 2000) 28 Beispiel Professor Name Dienstzimmer Tel 0..* Student 0..* Name Matrikelnummer prüft Datum Fach Anmerkung: Der bessere Primärschlüssel von Student wäre Matrikelnr. Ich möchte aber im Folgenden auch zeigen, wie man mit gleichbenannten Attributen unterschiedlicher Bedeutung umgeht. Datenbankschema Professor: Name, Dienstzimmer, Tel prüft: PName, SName, Datum, Fach Student: Name, Matrikelnr SQL-Schema CREATE TABLE Professor (Name VarChar(20) not null, Dienstzimmer VarChar(5), Tel integer, PRIMARY KEY (Name) ) Anmerkung: Der Primärschlüssel (primary key) einer Tabelle sollte immer definiert werden. CREATE TABLE Student (Name VarChar(20) not null, Matrikelnummer VarChar(10) not null, PRIMARY KEY (Name), UNIQUE (Matrikelnr) ) Hier wurde neben der Primary-Key-Bedingung noch eine weitere (vom System zu überprüfende) Integritätsbedingung angegeben. Jede Matrikelnummer muss eindeutig (unique) sein, d. h., zwei Studenten dürfen nicht dieselbe Matrikelnummer haben. Insbesondere bedeutet das, dass Matrikelnr ein Schlüsselkandidat – und zwar der bessere! – ist. 29 Draft (2. März 2000) CREATE TABLE prueft (PName VarChar(20) not null, SName VarChar(20) not null, Datum datetime[YY:MI] not null, Fach VarChar(20) not null, PRIMARY KEY (PName,SName,Datum,Fach), FOREIGN KEY (PName) REFERENCES Professor (Name), FOREIGN KEY (SName) REFERENCES Student (Name) ) Bei der Überführung eine Relationship in eine Tabelle werden zwei Fremdschlüssel-Integritätsbedingungen definiert (Fremdschlüssel = foreign key). Diese besagen, dass ein Tupel „Professor A prüft Student B“ nur existieren kann, wenn es sowohl den Professor A in der Tabelle Professor als auch den Studenten B in der Tabelle Student gibt. Das heißt, Student B kann beispielsweise nur gelöscht werden, wenn zuvor das obige Prüfungstupel ebenfalls gelöscht wurde referenzielle Integrität = alle Fremdschlüsselbedingungen werden erfüllt). Foreign Keys sollten bei „Relationship-Tabellen“ normalerweise immer definiert werden, wenn nicht triftige Effizienzgründe dagegen sprechen. 3.2.2 Optimiertes „Schema F“ Das vorgestellte Verfahren zur Überführung von ER-Diagrammen in Relationenschemata funktioniert für jedes ER-Diagramm, d. h., für beliebige Entitytypen und beliebige Relationen. Allerdings ist das Verfahren für 1:n-, n:1- und 1:1-Beziehungen nicht optimal, da man in beiden Fällen die spezielle „Relationshiptabelle“ einsparen kann ( D Join-Einsparung). 1:n/n:1-Beziehungen Person 0..* Lieblingsspeise Name Alter 1 Speise Name Joule Datenbankschema Person: Name, Alter, Lieblingsspeise(Name) Speise: Name, Joule Draft (2. März 2000) 30 SQL-Schema CREATE TABLE Person (Name VarChar(20) not null, Alter integer, Lieblingsspeise VarChar(20) not null, PRIMARY KEY(Name), FOREIGN KEY (Lieblingsspeise) REFERENCES Speise(Name) ) CREATE TABLE Speise (Name VarChar(20) not null, Joule integer, PRIMARY KEY (Name) ) "! #$% &E° ?´ ✎ ✎ 1:1-Beziehungen Angestellter 1 Personalakte 1 Persnr .. . Persnr .. . 1:1-Beziehungen kann man vollständig eliminieren, indem man einfach alle Attribute der beiden zugehörigen Entitytypen in einer Tabelle gemeinsam ablegt. Einen der beiden Primärschlüssel verwendet man als Primärschlüssel der gemeinsamen Tabelle. Das andere Primärschlüsselattribut kann komplett entfernt werden, wenn es sich um ein speziell definiertes Identifikationsattribut handelt, anderenfalls behält man es bei und definiert es als unique(<Attribut>). Optionale Beziehungen A 0..* 0,1 B Erweitere A um den anderen Fremdschlüssel (wie im Fall 1:n). Der Fremdschlüssel darf dabei auch den Wert Null annehmen (im Gegensatz zum Fall 1:n). Im obigen Beispiel mit der Lieblingsspeise wird Lieblingsspeise VarChar(20) not null durch Lieblingsspeise VarChar(20) ersetzt. 31 Draft (2. März 2000) A 0,1 0,1 B Erweitere A oder B um den anderen Fremdschlüssel. Der Fremdschlüssel darf auch den Wert Null annehmen. A 0,1 1 B Erweitere A um den anderen Fremdschlüssel. Der Fremdschlüssel darf nicht Null sein (da es zu jedem µh¶`ª ein ·­¶¹¸ geben muss). Man beachte allerdings, dass · ¶º¸ auch ohne µh¶`ª existieren kann. ER } Rel-Matrix Die Abbildungen einer ER-Beziehung A r B auf Relationenschemata abhängig von den Multiplizitäten kann man mit Hilfe einer Matrix zusammenfassen. » 0 ¸ zu µh¶[ª gibt es ½ » 1 =1 1 soviele ·¼¶º¸ ª ½ 1 =1 » » 0 1 R zu ·­¶º¸ gibt es soviele µa¶`ª R foreign key in ª references ¸ foreign key in ¸ references ª foreign key, not null Relationship als eigene Relation (+ Zusatzbedingungen) Komplexe Attributtypen Komplexe Attributtypen, wie set<Person>, list<Person> etc., werden durch die Einführung zusätzlicher Entitytypen und zusätzlicher Beziehungen eliminiert und wie zuvor behandelt. Draft (2. März 2000) 32 < = Auto < Auto Auto 4 Rad Räder: Rad[4] = 1 0..* Rad {Ein Auto hat 4 Räder} Person 0,1,2 Kinder Name: string 0..* < Person Name: string Kinder: list<Person> = Reduktion der Anzahl der Relationschemata Die Überführung eines ER-Modells in ein relationales Schema liefert unter Umständen mehrere Relationen mit gemeinsamen Schlüsselkandidaten. Derartige Relationen können zu einer Relation zusammengelegt werden D Joinvermeidung. Wenn H ¨¡ª H JBABABABJª­¾¼¯ und |¨Y¸ H JBABABA¢J1¸ K ¯ den gemeinsamen Schlüsselkandiª H JBABABABJª­¾¼ Á ¸ H JBABACA1J1¸ K haben, dann kann man daten H JBABABABJ¢¿ À H und / durch eine neue Relation O mit den Attributen ª H JCABABA¢JIª­¾¼ ¸ H JBACABA1J¢¸ K und dem Schlüsselkandidaten H JBACABA1J¢ ¿ ersetzen. Abteilung Name Nr Hardware 11 Software 13 Abteilungsleiter Nr Leiter 11 ’Müller, Hans’ 13 ’Meier, Schorsch’ D Abteilung Nr Name Leiter 11 Hardware ’Müller, Hans’ 13 Software ’Meier, Schorsch’ 3.3 Die Relationale Algebra und SQL Im Folgenden werden wir die klassische Lieferanten-DB als „running example“ nehmen. 33 Draft (2. März 2000) 0..n Lieferant 0..* Ware Wnr Typ Bezeichnung liefert Preis Lieferzeit Lnr Name Adresse Das zugehörige Relationenschema sieht wie folgt aus: Ware Wnr Typ Bezeichnung PRIMARY KEY (Wnr) Lieferant Lnr Name Adresse PRIMARY KEY (Lnr) liefert Wnr Lnr Preis Lieferzeit PRIMARY KEY (Wnr,Lnr) FOREIGN KEY (Wnr) REFERENCES Ware FOREIGN KEY (Lnr) REFERENCES Lieferant Wie bereits bekannt ist, sind Relationen Teilmengen des kartesischen Produktes der zugehörigen Domänen. Beispiele Lieferant Lnr Name 1 ’Maier’ 2 ’Müller’ 3 ’Maier’ Ware Wnr Typ Draft (2. März 2000) Adresse ’Königsbrunn’ ’Königsbrunn’ ’Augsburg’ Bezeichnung 34 1 2 3 4 . . . liefert Lnr 1 1 1 2 ’CPU’ ’CPU’ ’CPU’ Graphikkarte Wnr 1 2 3 3 " ÃÄ$Å%ÆÇÈÉÅÊ&ËÃÌEÍ ÆÇÈÉÅÊËÃÌ?Î Preis 50 300 150 170 ’Pentium 200’ ’Pentium II 330’ ’Celeron 330’ ’Matrox G200’ Lieferzeit 1 2 7 4 ✎ ✎ Unter einer relationalen Algebra versteht man eine Menge von relationalen Operationen, die eine oder mehrere Relationen (Tabellen) wieder auf Relationen abbilden. Die Algebra-Eigenschaft, dass die Ergebnisse relationaler Operationen immer Relationen sind, wird auch als Abgeschlossenheit bezeichnet. Die Abgeschlossenheit hat zur Folge, dass nacheinander beliebig viele relationale Operationen auf eine Tabelle angewendet werden können. 3.3.1 Die Identität Die einfachste relationale Operation ist die Identität ϡЮѲÒÓ Ô als Ganzes zurückliefert: Ò , die jede Relation Ï£Ð²Õ ÔÖ×Ô In SQL2 geschieht dies mit Hilfe eines speziellen Select-Befehls. select distinct * from Lieferant select distinct * from <komplexer relationaler Ausdruck> select distinct * from < Ô > Ø table <r>, wenn Ô duplikatfrei Man beachte, dass der select-Befehl Duplikate nur dann automatisch entfernt, wenn man select distinct schreibt. Anderenfalls (d. h. bei select oder select all) kann das Ergebnis Duplikate enthalten. Das heißt, SQL realisiert eine Multimengen-Semantik. Im Falle von Basis-Relationen (wie z. B. Lieferant) ist die Angabe von distinct allerdings nicht notwendig, da derartige Relationen immer ohne Duplikate gespeichert werden. 35 Draft (2. März 2000) 3.3.2 Die Projektion Die Projektion dient dazu, bestimmte Spalten aus einer beliebigen (d. h. gespeicherten oder berechneten Tabelle) zu selektieren. Wenn Ò©Õ£ÙwÚCÛBÜBÜBÜ¢ÛIÙ­Ý Ö eine Relation ist und Þqß-ÚCÛBÜBÜBÜ¢Û1ßàqá eine Teilmenge der Attribute, dann ist âãåä&æèç^ç^ç æ ã¬éê¤ëiì diejenige Tabelle, die aus Ò entsteht, wenn man alle übrigen Spalten aus Ò entfernt. Man beachte: dabei entstehende Duplikate müssen ebenfalls entfernt werden. Beispiel Ware 1 ’CPU’ 2 ’CPU’ 7 ’RAM’ 9 ’RAM’ â ’Pentium 200’ ’Celeron 300’ ’FP 16MB’ ’SD100 16MB’ Typ Õ Ware Ö ’CPU’ ’RAM’ Man kann die obige Definition der Projektion sogar noch erweitern: Jede Spalte der Ergebnisrelation wird mit Hilfe jeweils einer Funktion aus den Attributwerten von beliebig vielen (d. h. 0, 1 oder mehreren) Attributen der Ursprungsrelation berechnet: â²íîä¡ïíið æñIæ íóòYô ê íõ&ïíö ì ÕYÒ Ö â æ ’Sonderangebot’ ’Billig’+Typ Õ Ware Ö ’Sonderangebot’ ’BilligCPU’ ’Sonderangebot’ ’BilligRAM’ In SQL wird die Projektionsliste direkt nach dem Schlüsselwort select angegeben. select distinct Typ from Ware select distinct ’Sonderangebot’, ’Billig’||Typ from Ware Anmerkung: Die Verknüpfung (Konkatenation) zweier Zeichenketten erfolgt in SQL mit dem Verknüpfungsoperator || (und nicht wie sonst mit +). Wie bereits bekannt ist, darf in der Projektionsliste auch * stehen, als Abkürzung für die Liste aller Attribute einer Relation. Bisher habe ich meist eine abkürzende SQL-Schreibweise verwendet. Genaugenommen muss man zu jeder Relation in der From-Klausel auch noch einen Tupelbezeichner definieren. Den Tupelbezeichner kann man sich als Variablennamen vorstellen, der der Reihe nach alle Tupel der zugehörigen Relation durchläuft. In SQL ist allerdings eher die Auffassung üblich, dass der Tupelbezeichner lediglich ein Alias-Name für eine Relation ist. Draft (2. März 2000) 36 select select select select W.Typ from Ware W W.* from Ware as W // as ist optional ’Sonderangebot’, ’Billig’||W.Typ from Ware W ’Bruttopreis’, lief.Preis*1.16 from liefert lief Man kann sogar die Attributnamen mit as umbenennen: select W.T from Ware as W(Nr, T, Bez) Defaultmäßig wird der Relationenname selbst als Tupelbezeichner verwendet, auch wenn dies formal nicht ganz sauber ist. Ø select Typ from Ware select Ware.Typ from Ware Ware Wenn die Attributnamen der Projektionsliste völlig eindeutig sind (wie in unserem bisherigen Beispielen), kann man auf den Tupelbezeichner sogar verzichten. 3.3.3 Die Selektion Während die Projektion dazu dient, bestimmte Spalten einer Tabelle zu selektieren (und weiterzuverarbeiten), dient die Selektion dazu, bestimmte Zeilen einer Tabelle zu selektieren. Bei der Selektion wird für jedes Tupel ein boolesches Prädikat (welches von den Attributen der zugehörigen Relation abhängt) ausgewertet. ÷ Õ Ware Ö Typ=’RAM’ 7 ’RAM’ ’FP 16 MB’ 9 ’RAM’ ’SD100 16 MB’ ÷ ø Typ=’RAM’ Bezeichnung like ’SD%’ Õ Ware Ö 9 ’RAM’ ’SD100 16 MB’ SQL unterstützt folgende boolschen Operatoren: =, <=, >, >= und <> sowie OR, AND, NOT, IS [NOT] TRUE/FALSE/UNKNOWN/NULL, [NOT] BETWEEN ÜBÜBÜ AND ÜBÜBÜ und LIKE. Daneben werden auch noch Operatoren angeboten, die auf ganzen Tabellen arbeiten: [NOT] IN, MATCH, ALL, ANY, SOME, EXISTS, UNIQUE. Diese Operatoren werden Sie später kennenlernen. 37 Draft (2. März 2000) 3-wertige Logik Da Tabellen i. Allg. auch den Wert NULL enthalten können, realisiert SQL eine sogenannte 3-wertige Logik (three-valued logic). In dieser gibt es die drei Wahrheitswerte true (t), false (f) und unknown(u) mit folgenden Wahrheitsmatrizen: AND t u f t u f t u f u u f f f f OR t u f t u f NOT t t t t t u u t u f t u f f u t Außerdem müssen Arithmetikoperatoren, Vergleichsoperatoren etc. mit NULL umgehen können, wobei NULL als unbekannter und nicht als undefinierter Wert interpretiert wird: 5+NULL=NULL, 5>NULL ù UNKNOWN etc. Beispiel Es gebe drei Attribute A=3, B=4 und C=NULL. Dann gilt: A>B AND B>C A>B OR B>C A<B OR B<C NOT(A=C) ù ù ù ù false unknown true unknown Achtung: X IS FALSE ist nicht das Gegenteil von X IS NOT TRUE. X IS NOT TRUE heißt X IS FALSE OR X IS UNKNOWN. Anmerkung: Wenn man ausschließlich mit Attributen arbeitet, deren Domänen als NOT NULL deklariert wurden, reduziert sich die dreiwertige Logik von SQL auf die klassische zweiwertige Logik. ✎ ✎ " ÃÄ$Å%ÆÇÈÉÅÊ&ËÃÌEÎ ÆÇÈÉÅÊËÃÌ?úüûdýBÅþÉÿBÿ 3.3.4 Vereinigung, Durchschnitt, Differenz Relationen sind Mengen. Es können daher die Vereinigung, der Durchschnitt oder die Differenz zweier Relationen gebildet werden. Dabei muss allerdings darauf Draft (2. März 2000) 38 geachtet werden, dass die zugehörigen Relationen dieselben Attribute (Attributnamen und Attributdomänen) haben. Ò Õ¡ÙwÚ Ñ ÚBÛCÜBÜBÜBÛIÙ Ý Ñ Ý Ö Õ¡ÙwÚ ÑfÚCÛBÜBÜCÜBÛIÙ­ÝÑÝ Ö Ò Õ¡ÙwÚ Ñ ÚBÛCÜBÜBÜBÛIÙ Ý Ñ Ý Ö Õ¡ÙwÚ ÑfÚCÛBÜBÜCÜBÛIÙ­ÝÑÝ Ö Ò Õ¡ÙwÚ Ñ ÚBÛCÜBÜBÜBÛIÙ Ý Ñ Ý Ö Õ£ÙwÚ ÑfÚCÛBÜBÜCÜ1ÛIÙ Ý®ÑiÝ Ö In SQL gibt es zu diesem Zweck die Operationen union (mit Duplikatelimination), union all (ohne Duplikatelimination), intersect, intersect all, except und except all. Alle CPU und RAM-Bausteine: (select * from Ware where Typ=’CPU’) union (select * from Ware where Typ=’RAM’) Alle Lieferanten, deren Name nicht mit „M“ anfängt. (select * from Lieferant) except (select * from Lieferant where Name like ’M%’) Daneben gibt es noch die Möglichkeit, nur bestimmte gemeinsame Attribute zweier Relationen zu berücksichtigen und die anderen Spalten zu eliminieren. A union all corresponding by (x,y) B = (select x,y from A) union all (select x,y from B) Wenn by (x,y) weggelassen werden würde, würden alle gemeinsamen Attribute von A und B verwendet werden. " ÃÄ$Å%ÆÇÈÉÅÊ&ËÃÌEúüûdýBÅþÉÿBÿ ÆÇÈÉÅÊËÃÌ ✎ ✎ 3.3.5 Kartesisches Produkt und Join Zwei Relationen können mit Hilfe des kartesischen Produktes ( ) verknüpft werden. Lieferant liefert Lnr 1 1 1 1 Name ’Maier’ ’Maier’ ’Maier’ ’Maier’ Adresse ’Königsbrunn’ ’Königsbrunn’ ’Königsbrunn’ ’Königsbrunn’ 39 Lnr 1 1 1 2 WNr 1 2 3 3 Preis 50 300 150 170 Lieferzeit 1 2 7 4 Draft (2. März 2000) 2 2 2 2 3 3 3 3 ’Müller’ ’Müller’ ’Müller’ ’Müller’ ’Maier’ ’Maier’ ’Maier’ ’Maier’ ’Königsbrunn’ ’Königsbrunn’ ’Königsbrunn’ ’Königsbrunn’ ’Augsburg’ ’Augsburg’ ’Augsburg’ ’Augsburg’ 1 1 1 2 1 1 1 2 1 2 3 3 1 2 3 3 50 300 150 170 50 300 150 170 1 2 7 4 1 2 7 4 Mit Hilfe des kartesischen Produktes, der Selektion und der Projektion kann nun z. B. bestimmt werden, wer Waren innerhalb von einem Tag liefern kann. liefert Ö&Ö , wobei L ein Tupelbezeichner für Lieferant und lief ein Tupelbezeichner für liefert sei. â æ Name Adresse Lnr 1 // 1 // 1 1 2 2 2 // 2 3 3 3 3 Õ÷ L.Lnr=lief.Lnr AND Lieferzeit=1 Name Adresse Õ Lieferant Lnr WNr 1 /////////// ’Maier’ ’Königsbrunn’ ////////////////// 1// 2// /////////// ’Maier’ ’Königsbrunn’ //////////////////// 1// 3// ’Maier’ ’Königsbrunn’ 2 3 ’Müller’ ’Königsbrunn’ 1 1 ’Müller’ ’Königsbrunn’ 1 2 ’Müller’ ’Königsbrunn’ 1 3 /////////// ’Müller’ // ’Königsbrunn’ //////////////////// 2// 3// ’Maier’ ’Augsburg’ 1 1 ’Maier’ ’Augsburg’ 1 2 ’Maier’ ’Augsburg’ 1 3 ’Maier’ ’Augsburg’ 2 3 ’Maier’ ’Königsbrunn’ 1 //////// â ÷ ÷ Preis 50 300 ///// 150 ///// 170 50 300 150 170 ///// 50 300 150 170 Lieferzeit 1 2// 7// 4 1 2 7 4// 1 2 7 4 L.Lnr lief.Lnr Lieferzeit 1 æ Name Adresse In SQL wird das kartesische Produkt beliebig vieler Relationen einfach dadurch gebildet, dass mehrere Relationen (evtl. zusammen mit Tupelbezeichnern) in die From-Klausel geschrieben werden: select L.Name, L.Adresse from Lieferant L, liefert lief where L.Lnr=lief.Lnr and lief.Lieferzeit=1 Weitere Beispiele Welche Waren liefert Maier aus Königsbrunn? Draft (2. März 2000) 40 select W.Typ, W.Bezeichnung from Lieferant L, liefert lief, Ware W where L.Lnr=lief.Lnr and lief.Wnr=W.Wnr and L.Name=’Maier’ and L.Adresse like ’%Königsbrunn%’ Wer liefert welche Waren billiger als Maier aus Königsbrunn? select L.Name, L.Adresse, W.Typ, W.Bezeichnung, lief.Preis, liefM.Preis from // Ware der anderen Lieferanten Lieferant L, liefert lief, Ware W, // Ware von Maier (ohne Warenbezeichnung und -typ) Lieferant LM, liefert liefM where // Lieferant Maier LM.Name=’Maier’ and LM.Adresse like ’%Königsbrunn%’ and // liefert diese Waren: LM.Lnr = LiefM.Lnr and // Die anderen L.Lnr<> LM.Lnr and // liefern dies: L.Lnr=lief.Lnr and W.Wnr=W.Wnr and // Dieselbe Ware lief.Wnr=liefM.Wnr and // kostet weniger als bei Maier lief.Preis<liefM.Preis Man sieht, dass die Verwendung von Tupelbezeichnern unerlässlich ist, wenn man ein und dieselbe Relation mehrfach in der From-Klausel verwenden muss. " ÃÄ$Å%ÆÇÈÉÅÊ&ËÃÌ ÆÇÈÉÅÊËÃÌ ✎ ✎ Join-Operationen Das kartesische Produkt zusammen mit der Selektion reicht – von einem rein mathematischen Standpunkt aus gesehen – aus, um die Verknüpfung von zwei oder mehreren Tabellen zu beschreiben. In der Realität machen kartesische Produkte allerdings Probleme, da die Zwischenergebnisse sehr groß werden können. Die Anzahl der Elemente (Mächtigkeit) einer Menge bezeichnet man mit oÜ . Für Relationen Ò­ÚCÛBÜBÜCÜ1Û1Ò/Ý gilt: ^Ò­ÚÜBÜBÜºÒ Ý × èÒ ÚqÜBÜCÜèÒ/Ý 41 Draft (2. März 2000) Wenn wir z. B. 100 Lieferanten, 1000 Waren und 50000 liefert-Tupel haben, besteht das kartesische Produkt der fünf Relationen des letzten SQL-Beispiels aus ! " # $# ! " # ×&% $ ñ "' Ú !)( Tupeln. In Worten: 25 Billiarden Tupel. Wenn unser Rechner Tupel pro Sekunde abarbeiten kann, benötigt er also zur Beantwortung der gestellten Frage % "* $+ Sekunden = % "', Û- Jahre = 792,75 Jahre. Aus diesem Grund wurden die sogenannte Joinoperation eingeführt, die im wesentlichen kartesische Produkte gefolgt von speziellen Selektionen und Projektionen sind. Diese Spezialfälle können meist sehr effizient bearbeitet werden. Prädikatjoin Die allgemeinste (und i. Allg. ineffizienteste) Joinoperation ist der Prädikatjoin: Ò/.021 Ñ ×÷ 1²ÕPÒ3 Ö Dabei ist 4 ein Prädikat (wie 6 Ù 587:9`ß<;=" ), welches sich auf beliebige Attri bute von Ò und abstützt. Equijoin Wenn das Prädikat lediglich je ein Attribut (oder je eine Menge von Attributen) der beiden Relationen Ò und auf Gleichheit testet, spricht man von einem Equijoin: Ò/.0 ëfç í > ç ? Ñ ×:÷ ëfç í > ç ? ÕYÒ@ Ö Equijoins sind sehr effizient realisierbar und kommen sehr häufig vor (siehe letztes SQL-Beispiel). Die Komplexität beträgt AÕèÒB$CEDF'èÒG$H@ $CID#F' $H3 <Ergebnis> Ö . Falls das Ergebnis klein ist, kann die letzte Größe vernachlässigt werden. Das Ergebnis ist nur dann groß, wenn ein und derselbe Attributwert in sehr vielen Tupeln vorkommt, wie z. B. Geschlecht: weiblich oder männlich. Falls jedoch jedes Tupel der kleineren Relation im Durchschnitt nur einen Joinpartner hat, ist das Ergebnis so groß wie die kleinere Relation, d. h. AÕ <Ergebnis> Ö$× AÕ min Þ^ÒGoÛ# èá Ö 5:AÕJèÒG#$CID#F'èÒG Ö und AÕ $CEDF' Ö . Insbesondere Schlüsselattribute kommen in einer Relation nicht mehrfach vor. Das heißt, wenn z. B. eine Relation Ò über ein Schlüsselattribut (von Ò ) mit gejoint wird, gilt <Ergebnis> K . ✎ L*þÅÈMNPO*źþRQSMTqËÈVUwÄWN$ÊYXiÈjþÃUþRZ Ä*ÅÊW[qÇÈ]\2^`_¹ÅÈÌ*Åa^`b­ÉÌ*ÇÈþ \2Mc¹ËÊÅÊîÅÈTqÉRd$È]\#e Unter der Annahme, dass die Ergebnisgröße bei der Bestimmung der Zeitkomplexität vernachlässigt werden kann, ergeben sich beispielsweise folgende Laufzeitunterschiede: Angenommen èÒG × × $( Draft (2. März 2000) 42 $ Úgf ! ( Tupel/sec ^ÒG# × Û h Ûi"-' Konstante1 Tage kartesisches Produkt ^ ÒG log ^ ÒG$H3 $$CID#Fj × $( klH $( k × % !)( Û $)( Tupel m sec h % Konstante2 Sekunden Join Naturaljoin Der Naturaljoin ist ein Equijoin über gleichbenannte Attribute der Relationen R und S. Wenn Ò©Õ¡ÙwÚCÛBÜBÜCÜBÛIÙon­Û1ß-ÚCÛBÜBÜCÜ1Û1ß à Ö und Õp7­ÚCÛBÜBÜBÜ¢Û7 ÝÛ1ß-ÚCÛBÜBÜBÜ¢Û1ß à Ö dann: Ò/.0 Ñ × â íîä æ^çèç^ç æ íq æã ä æèç^ç^çæã¬éBæ ? ä æ^çèç^çæ ? q ÕPÒ:.0 ëfç ãsr > ç ãsr Ö Semijoin Der Semijoin ist ein Spezialfall des Naturaljoins, der nur die Attribute von R als Ergebnis liefert: Ò@t Ñ × â í äYæ^ç^çèçæ íq æ ãåä&æèç^çèç æãé ÕPÒ=.0 Ö Der Semijoin ist eine spezielle Selektion: Aus wählt, die in einen Joinpartner haben. Ò werden diejenigen Tupel ausge- Effizienz Der Naturaljoin lässt sich genauso effizient wie der Equijoin implementieren (Er ist ja nichts weiter als ein Equijoin mit anschließender Projektion). Der Semijoin kann sogar noch etwas effizienter implementiert werden, da die Tupel von nicht weiterverarbeitet werden müssen. Optimierung In SQL schreibt man Joins meist nicht explizit hin, sondern überlässt es den Optimierern, eine möglichst optimale Joinoptimierung des kartesischen Produktes Ý vorzunehmen. Dies ist allerdings sehr schwierig, da es AÕ`uwv Ö × AÕ`u Ö mögli ! % , v × ,Sk %xSx ). Es gibt Meche Joinvarianten für u Relationen gibt ( "sv × Ý Ú`y × $ %)z , thoden eine sehr gute Joinreihenfolge mit der Komplexität AÕ % Ö ( % $ % f{y × zx "|-}k ) zu bestimmen. Für u~; ist auch das noch zuviel – vor allem, wenn Anfragen interaktiv ausgewertet werden sollen. Dafür gibt es heuf $ f × ! , ristische Verfahren zur Joinoptimierung mit der Komplexität AÕ`u Ö ( % f ×:z ). Allerdings können diese Verfahren normalerweise nicht auf beliebige, sondern nur auf spezielle zu joinende Relationen angewendet werden. Explizite Joins in SQL Da es sehr schwierig ist, eine optimale Joinreihenfolge automatisch zu bestimmen, ist es in SQL auch möglich, Joins in der FROM-Klausel explizit anzugeben. 43 Draft (2. März 2000) Kartesisches Produkt: (cross join) select L,A,P,Z from (Lieferant cross join liefert) as Lcl (Lnra, L, A, Lnrb, Wnr, P, Z) Anmerkung: Bei der expliziten Angabe des zu verwendenden Joinoperators wird normalerweise immer der Alias-Operator as verwendet, um das Joinergebnis zu benennen. Hier heißt das, dass sowohl in der Select-Klausel als auch in der where-Klausel nur noch auf die (temporär erzeugte) Tabelle Lcl zugegriffen werden kann, nicht aber auf die ursprünglichen Tabellen Lieferant und liefert. Naturaljoin select Name, Preis // select lieferbar.Name, lieferbar.Preis from (Lieferant natural join liefert) as lieferbar; Hier verschattet die (temporär erzeugte) Relation lieferbar die ursprünglichen Tabellen Lieferant und liefert. Anmerkung: Wenn es keine gemeinsamen Attribute gibt, degeneriert der Naturaljoin zum Kreuzprodukt. Prädikatjoin select Name, Preis from ( Lieferant join liefert on Lieferant.Lnr = liefert.Lnr ) as lieferbar; h select * liefert als Ergebnis zwei Lnr-Spalten, da beliebige Joinbedingungen angegeben werden können (z. B. Lieferant.Lnr < Liefert.Lnr). Das heißt, in den beiden Lnr-Spalten können pro Tupel durchaus unterschiedliche Werte stehen. Equijoin select Name, Preis from ( Lieferant join liefert using (Lnr) ) h select * liefert als Ergebnis eine Lnr-Spalte, da beide Spalten für jedes Tupel immer denselben Wert enthalten. ✎ ✎ " ÃÄ$Å%ÆÇÈÉÅÊ&ËÃÌ ÆÇÈÉÅÊËÃÌ1ÿ Draft (2. März 2000) 44 Outer Joins Elemente einer Tabelle Ò , die keinen Joinpartner in einer Tabelle finden, erscheinen nicht im Ergebnis von Ò@.0 . Manchmal benötigt man allerdings alle Elemente der Tabelle Ò , unabhängig davon, ob es einen passenden Joinpartner gibt oder nicht. Dies ist mit Hilfe der sogenannten Outer-Joins möglich. Der Left-Outer-Join sorgt dafür, dass die linke Tabelle vollständig erhalten bleibt, der Right-Outer-Join, dass die rechte Tabelle erhalten bleibt und der Full-OuterJoin, dass beide erhalten bleiben. Der Natural-Left-Outer-Join, beispielsweise, ist wie folgt definiert: select * from R NATURAL LEFT JOIN S Ø (Pseudo-SQL) ( select * from R NATURAL JOIN S ) union all ( select *, NULL, ÜBÜBÜ , NULL from R where * not in (select R.* from R NATURAL JOIN S) ) Beispiel R Name Waren Maier Lampen Müller Rechner R .0 S Maier Lampen S Name Tel Maier 123 Huber 234 123 R .0 left S Maier Lampen 123 Müller Rechner Null R .0 right S Maier Lampen Huber Null R .0 full Maier Müller Huber 123 234 S Lampen 123 Rechner Null Null 234 Daneben gibt es noch den Union Join, der überhaupt keine Joinpartner sucht, sondern nur NULLs als Joinpartner einsetzt. 45 Draft (2. März 2000) R union join S Maier Lampen Müller Rechner Null Null Null Null Null Null Maier Huber Null Null 123 234 Zusammenfassung SQL unterstützt folgende expliziten Joins: CROSS JOIN JOIN LEFT JOIN RIGHT JOIN FULL JOIN UNION JOIN = = = = INNER JOIN (Prädikatjoin) LEFT OUTER JOIN RIGHT OUTER JOIN FULL OUTER JOIN NATURAL JOIN = NATURAL INNER JOIN (Naturaljoin) NATURAL LEFT/RIGHT/FULL JOIN (ohne ON oder USING-Klausel) Kreuzprodukt und Inner Join werden nur benötigt, um dem Optimierer Arbeit abzunehmen. In einem ersten Schritt ist die Verwendung dieser Operatoren daher meist unwichtig. Outer Join und Union Join sind dagegen echte Erweiterungen, die im Zusammenhang mit Nullwerten stehen. 3.3.6 Division Der Divisionsoperator dient dazu, allquantifizierte Fragen ( ÜBÜCÜ gilt für alle ÜCÜBÜ ) zu beantworten. Er ist im wesentlichen die Umkehroperation des Kreuzproduktes ( ÕYÒ@ Ö× Ò ). Der Divisionsoperator ist wie folgt definiert: Es sei Ù × Þ|Ù Ú ÛBÜBÜBÜ¢ÛIÙ gehören. Dann gilt: Ýá die Menge derjenigen Attribute von Ò = Ñ × â í ÕYÒ Ö â í Õ&Õ¡â í ÕYÒ Ö Ö Ò Ö Beispiel liefert Lnr Wnr 1 1 1 2 Draft (2. März 2000) Ware Wnr 1 2 46 Ò die nicht zu 1 2 2 3 1 2 3 Welcher Lieferant liefert alle Waren? Ù × Þ Lnr Û Wnr á Þ Wnr á × Þ Lnr á Es gibt zwei Lieferanten: â Lnr Õ liefert Ö 1 2 Wenn jeder alles liefern würde, hätten wir folgende Tabelle: â Lnr Õ liefert Ö Ware 1 1 1 2 2 2 1 2 3 1 2 3 Allerdings liefert Lieferant 2 Ware 2 nicht: Õ£â Lnr Õ liefert Ö Ware Ö liefert 2 3 Das heißt, Lieferant 2 liefert nicht alles: â Lnr ÕÕ¡â Lnr Õ liefert Ö Ware Ö liefert Ö 2 Wenn man von der Liste aller Lieferanten diejenigen abzieht, die nicht alles liefern, bleiben nur diejenigen Lieferanten übrig, die alles liefern. Hier heißt das, dass nur Lieferant 1 alles liefert: â Lnr Õ liefert Ö â Lnr ÕÕ£â Lnr Õ liefert Ö Ware Ö liefert Ö 1 Realisierung in SQL Der Divisionsoperator kann relativ effizient realisiert werden, er wird dennoch von SQL nicht unterstützt. Das heißt, man muss ihn – z. B. analog zur Definition des Divisionsoperators – durch andere Operatoren nachbilden. Die Realisierung des 47 Draft (2. März 2000) Kreuzproduktes wäre allerdings zu teuer. Effizienter ist es, den exists-Operator (Es gibt ein ÜBÜBÜ ) von SQL einzusetzen. Man beachte, dass folgende Beziehung zwischen Für alle und Es gibt ein . . . gilt: Für alle gilt ÜBÜBÜ ist gleichwertig zu Es gibt kein , für das 4Õ Ö 4 Õ Ö ÜBÜBÜ nicht gilt Die Anfrage „Welcher Lieferant liefert alle Waren?“ kann also folgendermaßen formuliert werden: select distinct l1.Lnr from liefert l1 where <l1 liefert jede Ware> Ø select distinct l1.Lnr from Liefert l1 where <Es gibt keine Ware, die l1 nicht liefert> Das heißt, wir müssen zunächst die Frage klären, welche Waren l1 nicht liefert. select Wnr from liefert l2 where l2.Lnr = sagt uns, welche Waren der Lieferant liefert. Durch Differenzbildung erfahren wir, welche Ware er nicht liefert: (select W.Wnr from Ware W) except (select l2.Wnr from liefert l2 where l2.Lnr = ) Nun können wir den not-exists-Operator von SQL einsetzen, um unsere ursprüngliche Frage zu beantworten. select distinct l1.Lnr from liefert l1 where not exists ( ( select W.Wnr from Ware W) except ( select l2.Wnr from liefert l2 where l2.Lnr = l1.Lnr) ) ✎ ✎ ✎ " ÃÄ$Å%ÆÇÈÉÅÊ&ËÃÌ1ÿ ÆÇÈÉÅÊËÃÌ ýÅþÉ!Cÿ N$ÊÉ Å \`UJ\d Å ÅþÊ Z$þÅÉ MNPO*źþRQaM`Ê&ÅaMÈN*ËÊMÈjÉþRQSMºÄ*þÊTqË\dþÅÈ]\#e Draft (2. März 2000) 48 Man spricht hier von einer korrelierten Subanfrage (correlated subquery), da die Hilfsanfrage in der Where-Klausel auf Variablen der übergeordneten Anfrage (hier l1.Lnr) Bezug nimmt. In diesem Fall muss die Subanfrage für jeden Lieferanten einzeln ausgewertet werden. Eine nicht-korrelierte Subanfrage braucht dagegen nur ein einziges Mal ausgewertet zu werden. Andere Möglichkeiten der Realisierung in SQL Die Anfrage select * from liefert l2 where l2.Lnr = and l2.Wnr = liefert ein Ergebnis genau dann wenn Lieferant die Ware liefert. Anderenfalls ist das Ergebnis die leere Tabelle. Das heißt, wir können die Waren, die nicht liefert, auch mit Hilfe einer korrelierten Subanfrage ermitteln. select * from Ware W where not exists ( select * from liefert l2 where l2.Lnr = and l2.Wnr = W.Wnr ) Und damit können wir unsere ursprüngliche Frage nach den Lieferanten aller Waren mittels zwei verschachtelter korrelierter Subanfragen formulieren: select distinct l1.Lnr from liefert l1 where not exists ( select * from Ware W where not exists ( select * from liefert l2 where l2.Lnr = l1.Lnr and l2.Wnr = W.Wnr ) ) Diese Art der Formulierung der Division in SQL ist sehr umständlich und auf den ersten Blick unverständlich. Es gibt aber leider keine einfachere Möglichkeit, da Allquantifizierung von SQL nicht unterstützt wird. Dritte Möglichkeit der Realisierung in (Nicht-Standard-)SQL In einigen Datenbanksystemen (z. B. in TransBase von TransAction Software GmbH) ist es auch möglich, Mengen zu vergleichen: =, <>, <= (subset) etc., 49 Draft (2. März 2000) auch wenn dies im SQL2-Standard nicht vorgesehen ist. Damit kann die Frage, welcher Lieferant alle Waren liefert relativ „natürlich“ formuliert werden: select distinct * from Lieferant L where ( <Alle Waren, die L liefert> ) = ( <Alle Waren, die es gibt> ) Das heißt: select distinct * from Lieferant L where ( select lief.Wnr from liefert lief where lief.Lnr = L.Lnr ) = ( select W.Wnr from Ware W ) ✎ ✎ " ÃÄ$Å%ÆÇÈÉÅÊ&ËÃÌüûdýBÅþÉwBÿ ÆÇÈÉÅÊËÃÌp ûdýÅbþÉÿBÿ 3.3.7 Subanfragen (Subqueries) In Abschnitt 3.3.6 wurden sogenannte Subanfragen zur Beantwortung bestimmter Anfragen eingesetzt. Die Möglichkeit von Subanfragen sollen hier genauer untersucht werden. Achtung: Ich gehe im Folgenden davon aus, dass alle Tabellen in Subanfragen keine Nullwerte enthalten. Die Behandlung von Nullwerten in diesem Zusammenhang würde den Vorlesungsrahmen sprengen. Subanfragen können sowohl in SQL-Projektionslisten (Select-Klauseln) als auch in SQL-Selektionslisten (Where-Klauseln) als auch in From-Klauseln stehen. Allerdings muss jede Subanfrage in einer Projektionsliste genau ein Element als Ergebnis liefern. Beispiel einer Projektionsliste mit Subanfragen select (select Autor from Autor where DOCID=5), (select Titel from Titel where DOCID=5) from dummy; â Autor êE DOCID=5 ê Autorìyìjæ Draft (2. März 2000) Titel êE DOCID=5 ê Titelìyì Õ dummy Ö 50 Hier sind Autor und Titel zwei Tabellen mit einem Attribut, das wie die Tabelle selbst heißt, und einem Primärschlüssel DOCID. Die Tabelle dummy enthält lediglich ein einziges Element für dessen Inhalt wir uns nicht weiter interessieren. Es wird aus syntaktischen Gründen benötigt, da in SQL2 immer eine From-Klausel vorhanden sein muss. (In Oracle gibt es zu diesem Zweck standardmäßig die Dummy-Tabelle dual.) Im Weiteren werden wir uns nicht mehr mit der Projektionsliste, sondern nur noch mit der where-Klausel befassen. Die in-Bedingung Die aus der Mengenlehre bekannte ist-Element-von-Beziehung ( ) gibt es auch in SQL: in not in =some <>all match Beispiel Welcher Lieferant liefert den Artikel mit Warennummer 3? select distinct L.Name from Lieferant L where L.Lnr in ( select lief.Lnr from liefert lief where lief.Wnr = 3) Oder in Relationaler-Algebra-Notation: â L.Name Õ÷ lief.Lnr êE lief.Wnr ð1ê liefert lief ìyìYÕ Lieferant L Ö&Ö Hier handelt es sich um eine nicht-korrelierte Subanfrage, die nur ein einziges Mal berechnet werden muss. Man könnte die Anfrage allerdings auch mit Hilfe einer korrelierten Subanfrage formulieren: select distinct L.Name from Lieferant L where 3 in ( select lief.Wnr from liefert lief where lief.Lnr = L.Lnr) oder (noch schlimmer): select distinct L.Name 51 Draft (2. März 2000) from Lieferant L where exists ( select * from liefert lief where lief.Lnr = L.Lnr and lief.Wnr = 3 ) Schließlich kann man die Anfrage auch ganz einfach als (Semi-)Join formulieren: select distinct L.Name from Lieferant L, liefert lief where L.Lnr = lief.Lnr and lief.Wnr =3 Am effizientesten auszuwerten sind i. Allg. die letzte und die erste Anfrage, da man beide mit Hilfe eines Semijoins realisieren kann. Die Anfragen mit korrelierter Subanfrage werden dagegen von den meisten SQL-Systemen wesentlich weniger effizient ausgewertet. Diese Möglichkeiten wurden auch eher als abschreckende Beispiele gebracht. Immerhin sieht man daran, dass die Verknüpfung von Tabellen auch ohne Join möglich ist, wenn Subanfragen unterstützt werden. Man muss also als Programmierer immer aufpassen, ob es im Falle von (korrelierten) Subanfragen nicht auch einfachere – und effizientere Lösungen gibt. Der in-Operator wird häufig verwendet, wenn man am Vergleich mit einer Vielzahl von Elementen interessiert ist: select * from Ware where Typ in (’CPU’,’RAM’,’GRAPHIKKARTE’); anstelle von select * from Ware where Typ = ’CPU’ or Typ = ’RAM’ or Typ = ’GRAPHIKKARTE’; Die obige Schreibweise ist eine Abkürzung für: select * from Ware where Typ in (values ’CPU’, ’RAM’, ’GRAPHIKKARTE’); Mit dem Schlüsselwort values kann in SQL2 eine anonyme, d. h. namenlose Tabelle temporär erzeugt werden: values (1, ’Maier’, ’Königsbrunn’), (2, ’Müller’, ’Augsburg’) Allerdings wird dieser Mechanismus von vielen Datenbanken zurzeit nur im Zusammenhang mit dem insert-Befehl unterstützt. Die obige Schreibweise (Typ in (’CPU’, ÜBÜBÜ )) wird dagegen von den meisten Datenbanken unterstützt. Draft (2. März 2000) 52 Noch’n Beispiel Welche Lieferanten liefern zumindest einige derjenigen Waren, die Lieferant 1 liefert (nur Lieferantennummern): select distinct l.Lnr from liefert l where l.Wnr in ( select l.Wnr from liefert l where l.Lnr = 1) Man beachte, dass l.Wnr außerhalb der Subanfrage eine andere Bedeutung hat als innerhalb. Man könnte zur Verdeutlichung außerhalb auch überall l1 und innerhalb überall l2 schreiben. Andererseits könnte man in diesem Fall – da es sich um eine nicht-korrelierte Subanfrage handelt – auch auf alle fett geschriebenen Tupelbezeichnungen (Aliasnamen) völlig verzichten. Ich tendiere allerdings dazu, immer eindeutige Tupelbezeichner zu verwenden, da man diese – als menschlicher „Parser“ – besser, d. h. fehlerfreier lesen kann. Der Match-Operator Wie bereits erwähnt wurde, bedeutet <Wert> match <Tabelle> dasselbe wie <Wert> in <Tabelle>. Daneben gibt es noch den Operator match unique: <Wert> match unique <Tabelle>. Dieser Test liefert nur dann true, wenn die Tabelle genau ein Element besitzt – und zwar <Wert>. Im Zusammenhang mit Nullwerten gibt es noch weitere Match-Varianten, die hier aber nicht diskutiert werden sollen. Die All- und Some-Operatoren Es gibt die Möglichkeit einen Wert mit allen (all) oder einigen Elementen – d. h. mindestens einem Element (some, any) zu vergleichen. Billiger als alle: Preis <=all (select Preis from liefert where ÜBÜCÜ ) Billiger als irgendeiner (nicht der teuerste): Preis <some (select Preis from liefert where ÜBÜCÜ ) Es gibt all und some (= any) für die Operatoren =, <, <=, >, >= und <>. Wie bereits gesagt wurde, gilt in = =some und not in = <>all. 53 Draft (2. März 2000) Achtung: In Umgangsenglisch kann any nicht nur irgendeiner/s, sondern auch jeder bedeuten (Get those parts whose price is less than that of any blue part.) Aus diesem Grund ist es besser immer some anstelle any zu verwenden. ✎ ✎ " ÃÄ$Å%ÆÇÈÉÅÊ&ËÃÌpaýÅþÉ|ÿBÿ ÆÇÈÉÅÊËÃÌ ýÅþÉ!Cÿ Der Exists-Operator Dieser Operator dient dazu, festzustellen, ob eine Tabelle leer ist oder nicht. exists <Tabelle> Verwendungsmöglichkeiten – insbesondere zur Realisierung des Allquantors – wurden bereits ausführlich diskutiert. Der Unique-Operator Dieser Operator kann genutzt werden, um festzustellen, ob in einer Tabelle Duplikate vorkommen (false) oder nicht (true): unique <Tabelle> Achtung: unique funktioniert nur mit der SQL-Multimengensemantik, nicht aber mit der Mengensemantik der relationalen Algebra (da Mengen niemals Duplikate enthalten). Beispiel Welche Artikel werden von mehreren Händlern zum billigsten Preis angeboten? select W.Wnr, W.Name from Ware W where not unique ( select W.Wnr // oder l1.Wnr oder ’Wert ist egal’ from liefert l1 where l1.Wnr = W.Wnr and l1.Preis <=all ( select l2.Preis from liefert l2 where l2.Wnr = W.Wnr ) ) Andere Lösung (mit Gruppierung und Aggregation; siehe Abschnitt 3.4) select l1.Wnr Draft (2. März 2000) 54 from liefert l1 where l1.Preis <=all ( select l2.Preis from liefert l2 where l2.Wnr = l1.Wnr ) group by Wnr having count(l1.Lnr) > 1 Man beachte, dass man dieselbe Anfrage auch mit reiner Mengensemantik beantworten kann, d. h. ohne den Operator unique und ohne Aggregation. Allerdings ist dies deutlich aufwendiger, da man dazu zwei exists-Operatoren benötigt: Es gibt einen Lieferanten L1, der zum billigsten Preis liefert, und es gibt einen zweiten Lieferanten L2 × L1, der ebenfalls zum billigsten Preis liefert (SQL-Query selbst formulieren!). " ÃÄ$Å%ÆÇÈÉÅÊ&ËÃÌ ýÅþÉBÿ ÆÇÈÉÅÊËÃÌüûdýÅbþÉÿBÿ ✎ ✎ 3.4 Aggregation und Gruppierung SQL bietet neben den Standard-RelAlg-Operatoren auch noch Aggregation und Gruppierung. Diese sind für die Praxis sehr wichtig (bedeuten aber für die zugrundeliegende Theorie deutlich mehr Aufwand). 3.4.1 Aggregation ohne Gruppierung Wie lautet der Durchschnittspreis des Artikels Nr. 3? select avg(Preis) from liefert where Wnr = 3 Wieviele verschiedene Artikel werden derzeit angeboten? select count(*) from Ware oder genauer (wenn lieferbare Waren gemeint sind): select count(*) from (select distinct Wnr from liefert) 55 Draft (2. März 2000) oder kürzer select count(distinct Wnr) from liefert In allen diesen Fällen wird eine Menge von Tupeln auf einen einzigen Wert abgebildet. Diesen Vorgang nennt man Aggregation. SQL unterstützt folgenden Aggregationsfunktionen count: Zähle Elemente sum: Bilde (numerische) Summe avg: Bilde (numerischen) Durchschnitt min: finde Minimum max: finde Maximum Bei allen Aggregationsfunktionen kann man bestimmen, ob Duplikate berücksichtigt werden sollen (all = Defaultwert) oder nicht (distinct). Für die Minimum- und Maximum-Berechnung macht dies allerdings keinen Unterschied. Aggregatfunktionen können nicht geschachtelt werden: select avg(sum(x)) ÜBÜBÜ ist Nonsense. 3.4.2 Aggregation mit Gruppierung Tabellen können vor der Aggregation in Gruppen eingeteilt werden. Die Aggregation wird dann für jede Gruppe separat durchgeführt. Im Gegensatz zur Aggregation ohne Gruppierung liefert die Aggregation mit Gruppierung i. Allg. mehr als ein Element als Ergebnis (und zwar für jede Gruppe eines). Beispiel liefert Lnr Wnr 1 1 2 1 3 1 1 2 3 2 Preis 50 100 150 50 100 Wie lautet der Durchschnittspreis der einzelnen Waren? Hier müssen die Daten also nach den Lieferanten gruppiert werden: Draft (2. März 2000) 56 select Lnr, avg(Preis) from liefert group by Wnr; Ergebnis Wnr avg(Preis) 1 100 2 75 Man beachte: Wenn in der Projektionsliste Aggregatsfunktionen aufgerufen werden, dürfen Gruppierungsattribute aus der group-by-Klausel nur ohne Aggregatsfunktion in der Projektliste stehen. Alle anderen Attribute dürfen nur mit Aggregatsfunktion in die Projektionsliste geschrieben werden. " ÃÄ$Å%ÆÇÈÉÅÊ&ËÃÌ ýÅþÉ|ÿBÿ ÆÇÈÉÅÊËÃÌpaýÅþÉ!Cÿ ✎ ✎ Man kann auch Bedingungen für ganze Gruppen angeben: Alle Gruppen mit mehr als drei Elementen, mit einem Durchschnittspreis ; ÜBÜBÜ etc. Dazu gibt es die Having-Klausel, deren Attribute (genauso wie in der Projektionsliste) wie folgt aussehen müssen: group-by-Attribute werden ohne Aggregationsfunktion aufgerufen, alle anderen Attribute mit Aggregationsfunktion. Wie lautet der Durchschnittspreis für jeden Artikel billiger als 1000 DM, für den es mindestens drei verschiedene Preise (< 1000 DM) gibt? select from where group by having Wnr, avg(Preis) as Durchschnittspreis liefert Preis < 1000 // and Wnr < 100 erlaubt Wnr count (distinct Preis) >= 3; // and Wnr < 100 auch hier erlaubt Man beachte, dass die Bedingung Preis < 1000 nur in der Where-Klausel stehen darf, da sie gruppenunspezifisch ist. Die Bedingung count(distinct Preis) >= 3 darf dagegen nur in der Having-Klausel stehen, da sie eine gruppenspezifische Aggregatsfunktion beinhaltet. Bedingungen zu Gruppierungsattributen wie Wnr < 100 dürfen in beide Bedingungsklauseln eingefügt werden. Hier entscheidet der Geschmack. 3.5 Sortierung SQL realisiert nicht die Mengensemantik der Relationalen Algebra, sondern eine Multimengensemantik. Das heißt, Duplikate werden nicht automatisch ent57 Draft (2. März 2000) fernt. Dies ist z. B. für Aggregation notwendig. Allerdings realisiert SQL keine Listensemantik. Das heißt, die Reihenfolge der Ergebnistupel einer Anfrage ist nicht festgelegt und kann sich bei denselben Daten und denselben Anfragen von Datenbanksystem zu Datenbanksystem unterscheiden. Wenn es auf die Reihenfolge der Ergebnistupel ankommt, kann man daher ans Ende des äußersten Select-Statements immer eine Order-by-Klausel anhängen: Beispiel Sortiere die Lieferanten nach ihrer Adresse (= Wohnort) und innerhalb der Wohnorte alphabetisch: select * from Lieferant order by Adresse, Name Es können beliebig viele Attribute der Ergebnis-Projektionsliste in der Order-by-Klausel angegeben werden. Jedes Attribut kann dabei aufsteigend (ASC, default) oder absteigend (DESC) sortiert werden: select * from Lieferant order by Name desc 3.5.1 Zusammenfassung Eine Select-Anfrage sieht wie folgt aus (die Nummerierung bezeichnet dabei die zeitliche Abfolge der Abarbeitung): 5 1 2 3 4 6 7 ✎ select <Projektionsliste> from <Relationen + Joins> [where <Bedingung>] [group by <Gruppierungsattribute>] [having <Gruppenbedingung>] [union|except|intersect select [order by <Sortierungsattribute>] ÜCÜBÜ ] ÆÇÈÉÅÊËÃÌpaýÅþÉ!Cÿ 3.6 Modifikation des Datenbestandes Die relationale Algebra sagt nichts darüber aus, wie man einen Datenbestand erzeugt und pflegt. Sie geht einfach davon aus, dass eine Menge von Relationen Draft (2. März 2000) 58 bekannt ist. SQL bietet dagegen nicht nur die Möglichkeit, einen Datenbestand per Anfragesprache zu untersuchen (select), sondern auch ihn zu manipulieren (insert, delete, update). ÆÇÈÉÅÊËÃÌ ýÅþÉ|ÿCÿ ✎ 3.6.1 Insert Es gibt zwei Möglichkeiten, Daten in eine Datenbank via Insert einzufügen. 1. Direkt insert into Lieferant(Lnr,Name) values (4, ’Huber’) Anmerkung: Nicht aufgeführte Attribute werden mit einem Defaultwert (siehe unten) oder Null initialisiert. insert into Lieferant values ( (select max(Lnr)+1 from Lieferant), ’Huber’, ’München’) insert into Lieferant // Nicht-SQL2 table ( (4, ’Huber’, ’München’), (5, ’Meyr’, ’Rosenheim’) ) 2. per Select- Statement insert into Lieferant // SQL2 select * from (values (4,’Huber’,’München’), (5,’Meyer’,’Rosenheim’) ) insert into Lieferant select * from LieferantMuenchen Achtung: Neben dem Insert-Befehl bieten die meisten DBs noch die Möglichkeit, externe Daten (z. B. in einem festen ASCII/ISO-Latin-Format) direkt in die Datenbank einzulesen (spool in) oder direkt in eine externe Datei auszugeben (spool out). Der Spoolvorgang ist allerdings nicht standardisiert. 3.6.2 Delete Daten können aus einer Datenbank auch wieder gelöscht werden: 59 Draft (2. März 2000) Alle Maiers und Mairs und Maierhubers sollen gelöscht werden: delete from Lieferant where Name like ’Mai%r’ Alle Tupel sollen gelöscht werden: delete from Lieferant Um die ganze Tabelle zu entfernen, muss man allerdings Folgendes schreiben: drop table Lieferant (Gegenteil von create table) 3.6.3 Update Bestehende Datensätze können modifiziert werden. Alle Maiers erhöhen ihre Preise um 10 % und ihre Lieferfristen um einen Tag: update liefert set Preis = Preis*1.10, Lieferzeit = Lieferzeit+1 where Lnr in (select Lnr from Lieferant where Name = ’Maier’) Achtung: Ein Update kann auch auf Schlüsselattributen erfolgen, meist allerdings unter Performanzeinbußen. 3.6.4 Allgemeine Anmerkungen Bei Update- und Insert-Befehlen können die zwei Sonderwerte Null und Default angegeben werden. Default bezeichnet dabei den Defaultwert des aktuellen Datentypes. Der Programmierer kann den Defaultwert einer Tabellenspalte bei der Definition der entsprechenden Tabelle create table Lieferant (Name varchar(20) default ’???’, ÜBÜBÜ ) oder mit Hilfe von Domänendefinition create domain namestring as varchar(20) default ’???’ Draft (2. März 2000) 60 create table Lieferant (Name namestring, ÜBÜCÜ ) festlegen. Modifikation am Datenbestand sind nur unter bestimmten Bedingungen erlaubt: 1. Der Benutzer muss die entsprechenden Rechte besitzen. 2. Durch die Modifikation werden keine Integritätsbedingungen verletzt. 3. Die zugehörige Transaktion wird durch commit oder Autocommit beendet (und nicht etwa durch rollback verworfen). 4. Der Commit wird erfolgreich beendet. Insbesondere heißt das, dass keine der Integritätsbedingungen, deren Überprüfung bis zum Commitzeitpunkt verzögert wurden, auf einen Fehler läuft. 5. Die Datenbank wird nicht durch einen Recoveryvorgang im Katastrophenfall auf einen älteren Zustand zurückgesetzt. Modifikationsoperationen erfolgen zweistufig: Erst wird alles berechnet, was geändert werden soll, dann werden die Änderungen durchgeführt. Wäre dem nicht so, so wären die Ergebnisse folgender Operationen nicht vorhersagbar, da sich der Durchschnittspreis mit jedem Tupelupdate verändern würde: delete from liefert where Preis > (select avg(Preis) from liefert) update liefert set Preis = 0.9*Preis where Preis > 2*(select avg(Preis) from liefert) ÆÇÈÉÅÊËÃÌüûdýÅbþÉÿBÿ ✎ 3.7 Views ÆÇÈÉÅÊËÃÌ ✎ In SQL ist es möglich, sogenannte views (virtuelle oder berechnete Relationen) zu definieren. create view Liefer (Name, Adresse, Wnr, Preis, Dauer) as select L.Name, L.Adresse, 61 Draft (2. März 2000) lief.Wnr, lief.Preis, lief.Lieferzeit from Lieferant L, liefert lief where L.Lnr = lief.Lnr Eine view kann in Select-Anweisungen wie eine normale Relation (stored table) eingesetzt werden. select avg(Preis) from Liefer where Name=’Maier’ Insbesondere kann eine View auch zur Definition anderer Views eingesetzt werden. Falls allerdings eine View wieder gelöscht wird (z. B. drop view Liefer) sind alle anderen Views und alle Integritätsbedingungen, die sich auf diese View abstützen, ungültig. Man kann dies verhindern, indem man das Löschen entweder abbricht, wenn noch Abhängigkeiten bestehen (drop view <name> restrict), oder alle abhängigen Views und Integritätsbedingungen automatisch mitlöscht (drop view <name> cascade). Ein nachträgliches Ändern einer Views (alter view) ist im Gegensatz zu Tabellen (alter table) in SQL2 nicht möglich. Views können in SQL2 gar nicht und in SQL3 nur eingeschränkt rekursiv definiert werden. Das ist sehr schade, da damit SQL berechnungsvollständig (turingmächtig) wäre. Zum Beispiel könnte mit rekursiven Views das Pfadproblem (Welche Pfade führen – evtl. über mehrere Zwischenknoten – von A nach B?) gelöst werden. Das Pfadproblem tritt in der Praxis sehr häufig auf (Zugverbindungen, Flugverbindungen, Internetverbindungen, Vorfahren/Nachfahren/Verwandschafts-Beziehungen etc.). Beispiel Vorfahren Es sei Eltern(Kind,Elter) eine Relation, in der zu jeder Person Kind ein Elternteil Elter angegeben ist. Kind Elter Sibylle Sibylle Marianne Marianne Franziska . . . Wolfgang Marianne Jakob Franziska Theresia create view Vorfahren (Person, Vorfahre) as (select * from Eltern) // Abbruchbedingung union Draft (2. März 2000) 62 (select V.Person, E.Elter // Rekursion from Vorfahren V, Eltern E where V.Elter = E.Kind ) Diese View beschreibt folgende Vorfahren-Tabelle: Kind Sibylle Sibylle Marianne Marianne Franziska Elter Wolfgang Marianne Jakob Franziska Theresia Sibylle Sibylle Marianne Jakob Franziska Theresia 2. Generation Sibylle Theresia 3. Generation 1. Generation Verfahren, um rekursive Views effizient zu berechnen sind heute gut erforscht, allerdings auf dem Gebiet der sogenannten deduktiven Systeme. Deduktive Sprachen und Datenbanksysteme wurden in den letzten 15 Jahren erforscht, waren aber nicht sehr erfolgreich – und so werden die dabei gewonnenen Erkenntnisse bislang nicht in anderen Gebieten (wie z. B. RDBS) eingesetzt. Das ist insofern verwunderlich, da zwischen RDBS und deduktiven DBS (DDBS) – abgesehen von syntaktischen Unterschieden – nur ein wesentlicher Unterschied besteht: DDBS erlauben rekursive Views, RDBS dagegen nicht. Ein Problem der rekursiven Views ist, dass man die Ergebnisgröße eines Ergebh nisses nur sehr schwer abschätzen kann ( automatische Optimierung ist sehr schwer). Beispiel Wenn man u Netzknoten (Bahnhöfe, Flughäfen, Router etc.) hat und man berechnen will, von welchem Knoten zu welchem Knoten Verbindungen existieren, f enthält das Ergebnis zwischen u und u Tupel: u Jeder Knoten ist nur mit sich selbst verbunden. u f Jeder Knoten ist mit jedem verbunden. Leider lässt sich anhand statistischer Daten vor der eigentlichen Berechnung keine genauere Abschätzung durchführen. 63 Draft (2. März 2000) Die Tabellen Start 1 2 3 Ziel 1 2 3 4 . . . 4 u u Start 1 2 3 . . . Ziel 2 3 4 u u u 1 sind statistisch vollkommen gleichwertig (gleichviele Tupel, jeder Wert kommt in jeder Spalte gleichoft vor). Allerdings enthält die transitive Hülle, d. h. die Tabelle f aller möglichen Verbindungen im ersten Fall nur u Tupel im zweiten Fall u . Fazit: rekursive Views bereiten bei der Abschätzung von Kosten den Optimierern wesentlich mehr Probleme als nicht-rekursive Views. 3.7.1 Das View-Update-Problem Views wurden nicht erfunden, um rekursive Definitionen zu ermöglichen oder eine Verwandschaft zu den deduktiven Systemen herzustellen, sondern um bestimmten Benutzergruppen nur eine eingeschränkte Sicht (view!) auf die Datenbank zu erlauben. So könnte z. B. für die Inventarabteilung eine View erzeugt werden, die es den Mitarbeitern dieser Abteilung ermöglicht, Name, Zimmernr und Telefonnr aller Mitarbeiter, nicht aber deren Gehalt und Familienstand zu erfragen. Dazu müssen für die Mitarbeiter der Inventarabteilung eine oder mehrere Datenbankbenutzergruppen erzeugt werden, die lediglich das Recht haben, diese View zu lesen, nicht aber die Orginaltabelle. Ein nächster Schritt wäre, diesen Mitarbeitern auch gewisse Updates zu erlauben. In diesem Fall müssten die Befehle insert, delete und update auch für Views ermöglicht werden. Doch das ist nur sehr eingeschränkt möglich. Wenn z. B. eine View mit Hilfe zweier Relationen aufgebaut wurde, ist das Einfügen eines Tupels in die View in SQL2 nicht erlaubt, da i. Allg. nicht feststeht, welche ein(?) oder zwei(?) Tupel in die zugehörigen Relationen eingefügt werden sollen. In SQL2 sind Viewupdates nur unter ganz bestimmten Voraussetzungen erlaubt (updatable views): 1. Die View basiert auf genau einer Relation oder einer updatable view (kein Join, Union, Intersect, Except). 2. Select Distinct wurde nicht verwendet. 3. Es gibt deine Group-by- oder Having-Klausel. Draft (2. März 2000) 64 4. Es sind nicht alle Where-Klauseln erlaubt. 5. Jede Spalte der Select-Klausel ist ein Aliasname für eine Tabellenspalte (keine Arithmetik etc.). 6. Alle Spalten, für die keine Defaultwerte existieren (wie z. B. der Primärschlüssel), sind über die View zugänglich. Â"ÃÄ$Å%ÆÇÈÉÅÊ&ËÃÌ ✎ 65 Draft (2. März 2000) Draft (2. März 2000) 66 Kapitel 4 Oracle ÆÇÈÉÅÊËÃÌ?úüûdýBÅþÉwBÿ ✎ 4.1 SQLPlus rem: Zeilenkommentar /* */: Blockkommentar describe <table>: Relationenschema der Tabelle <table> spool <file>: Ausgabe in Datei <file> umlenken spool off: Ausgabe auf Bildschirm save <Datei>: SQL-Code sichern edit <Datei>: Editiere Datei mit Standardeditor host emacs <Datei>: Editiere Datei mit anderem Editor start <Datei>: Führe Inhalt der Datei aus show feedback: Zeige Inhalt einer SQLPlus-Variable set feedback off/set feedback 10: Setze Inhalt einer SQLPlus-Variablen typische Variablen feedback: gibt Anzahl Zeilen aus, wenn das Ergebnis mehr als feedback Zeilen hat numwidth: Anzahl Zeichen zum Darstellen von Nummern linesize: Länge einer Zeile in Zeichen pagesize: Anzahl Zeilen einer Seite newpage: Anzahl Leerzeilen zwischen zwei Seiten 67 Draft (2. März 2000) pause on/off/<text>: Aufforderung Enter zu drücken, um nächste Seite zu sehen Die Datei login.sql im aktuellen Verzeichnis kann SQLPlus-Befehle enthalten, die bei jedem Start von SQLPlus automatisch ausgeführt werden. prompt login.sql geladen! set feedback 6 set sqlprompt ’SQL>’ set numwidth 5 set pagesize 70 set linesize 132 define _editor = "vi" 4.2 Date Nullstellige Funktion SysDate: select SysDate from dual; SysDate 01-Nov-98 Die Tabelle dual hat eine Spalte und eine Zeile (Dummytabelle).1 Außerdem gibt es die Tabelle holiday mit amerikanischen Feiertagen. Datumsfunktionen – ADD_MONTHS(<Datum>,<Anzahl Monate>) – GREATEST(<Datum1>,<Datum2>, ÜBÜCÜ ) – LEAST(<Datum1>,<Datum2>, ÜBÜCÜ ) – LAST_DAY (<Datum>) letzter Tag des Monats – NEXT_DAY(<Datum>,<Wochentag>) nächster <Wochentag> nach <Datum> – MONTHS_BETWEEN(<Datum1>,<Datum2>) – TO_CHAR(<Datum>,<Format>) Datum in String umwandeln 1 Eine weitere Anwendung von dual: select 317*712+5 from dual; Draft (2. März 2000) 68 – TO_DATE(<String>,<Format>) String in Datum umwandeln – ROUND<Datum> runde taggenau – TRUNC<Datum> schneide Stunden, Minuten, Sekunden ab Mitternacht ab select TO_DATE(’02-APR-99’) - ROUND(SYSDATE) from dual; select TRUNC(SYSDATE) + 1 from dual; morgen select TRUNC(SYSDATE) + 0.5 from dual; heute Mittag Formatanweisungen Die Konvertierung von Zeichenketten in das Datumsformat und umgekehrt erfolgt über Formatstrings. Ein Formatstring kann Schlüsselwörter, Sonderzeichen und uninterpretierte Zeichenketten (" ÜCÜBÜ ") enthalten. Schlüsselwörter von Formatstrings: MM: Monat als Nummer RM: Monat als römische Nummer MON: 3-buchstabiger Monatsname (AUG) MONTH: Monatsname DDD: Tage seit Beginn des Jahres DD: Tage seit Beginn des Monats D: Tage seit Beginn der Woche DY: 3-buchstabiger Wochentag DAY: Wochentag YYYY: Jahr (4 Ziffern) YY: Jahr (2 Ziffern) IYYY: ISO-Jahr (4 Ziffern) IY: ISO-Jahr (2 Ziffern) Q: Quartal WW: Kalenderwoche IW: ISO-Kalenderwoche W: n-te Woche im Monat 69 Draft (2. März 2000) HH,HH12: Stunde 1-12 ✎ HH24: Stunde 1-24 MI: Minute SS: Sekunde SSSSS: Anzahl Sekunden seit Mitternacht Â"ÃÄ$Å%ÆÇÈÉÅÊ&ËÃÌEúüûdýBÅþÉwBÿ Draft (2. März 2000) 70 Kapitel 5 Datenbankensysteme und Multimedia SQL2 sieht bislang keine Unterstützung von Multimedia vor. Das wird sich allerdings mit SQL3 ändern. Doch praxistaugliche Implementierungen des SQL3-Standards wird es in den nächsten fünf bis zehn Jahren aller Voraussicht noch nicht geben. Hier soll nun untersucht werden, inwieweit bereits heutige Datenbanksysteme in Multimediaanwendungen, insbesondere in Internet-Anwendungen, eingesetzt werden können. 5.1 Anforderungen an ein Multimedia-Datenbanksystem Welche Eigenschaften sollte ein gutes MMDBS erfüllen? 1. Es sollte ein vollwertiges Datenbanksystem sein: – Persistenz (d. h., dauerhafte Speicherung der Daten) – Transaktionen (Robustheit im Fehlerfall) – Recovery (Robustheit im Katastrophenfall) – Mehrbenutzerfähigkeit – Integritätssicherung (Konsistenz) – Performanz – Ad-hoc-Anfragen – etc. 2. Es sollte Multimedia-Objekte (Daten + Methoden) unterstützen: Text (insbesondere HTML/XML), Bild, Audio, Video, komplexe multi-mediale Objekte h ( Interaktion, Synchronisation), Hyperlinks 3. Es sollte – für MM-Objekte – Informations-Retrieval-Fähigkeiten bieten – Attributsuche (einfach, da DBS dies bereits bietet) 71 Draft (2. März 2000) – Inhaltssuche (i. Allg. sehr schwierig), insbesondere Volltextsuche (nicht so schwierig) – navigierende Suche / Linkverfolgung (nicht so schwierig, wird aber derzeit nicht standardmäßig unterstützt) Vorteile von MMDBS 1. saubere Verwaltung großer Mengen an Multimediadaten (z. B. erzeugen Abbrüche von langen Kopiertransaktionen keine Dateileichen) 2. Schneller Zugriff auf einzelne Objekte (Gegenbeispiel: Unix-Directory mit 10 000 Objekten) 3. optimierte Ablage von MM-Objekten. Verwaltung von CD-ROM-Archiven (Jukeboxes), Bandarchieven, Plattenfarmen etc. 4. Datenbankeigenschaften: Mehrbenutzerbetrieb, Datensicherheit, Konsistenz (z. B. referenzielle Integrität)1 etc. 5. effizientes Information Retrieval 6. Und anderes mehr 5.2 Relationale Datenbanksysteme und Multimedia SQL2 bietet – bis auf den wenig performante LIKE-Selektor – keine MM-Unterstützung. Allerdings sind die Datenbankhersteller in diesem Punkt schon weiter: – Die meisten Datenbanken können BLOBs (Binary Large Objects) verwalten. – Volltextsuche wird von vielen Datenbanken unterstützt. – Oracle unterstützt Quicktime – Datenbanken auf CD-ROMs und CD-ROM-Jukeboxes werden unterstützt (z. B. TransBase). – Es ist möglich WWW-Seiten mit Datenbankunterstützung zu erstellen (z. B. PHP und JDBC). – Es gibt spezielle WWW-Datenbankserver (z. B. von Oracle). Leider sind diese Techniken und Spracherweiterungen derzeit meist proprietärer Natur. Das heißt, jeder Hersteller kocht sein eigenes Süppchen. Es gibt allerdings 1 Die referenzielle Integrität ist eine der wesentlichsten Schwachstellen der WWW: URLs zeigen häufig ins Nirwana. Draft (2. März 2000) 72 Bestrebungen auch in diesen Bereichen Standards – wie z. B. SQL3 – zu etablieren. 5.2.1 BLOBs Normale SQL-Datentypen wie varchar oder binchar sind längenbeschränkt (z. B. 4 KByte). Um große (binäre) Datensätze in Datenbanksystemen zu speichern wurden deshalb die sogenannten BLOBs (Binary Large Objects) eingeführt. Allerdings dürfen auch BLOBs nicht beliebig groß sein. So darf ein BLOB in TransBase nicht größer als 2 GB (-1 % Overhead) und in Oracle 8 nicht größer als 4 GB (glaube ich) sein. In TransBase ist die Größe einer Tabelle außerdem auf 4 Terrabyte (-1,5 % Overhead) beschränkt (Oracle: weiß ich noch nicht). Dies reicht für die meisten Anwendungen aus, kann aber zu Engpässen im Videobereich führen. Oracle hat angekündigt, in Zukunft auch BLOBs beliebiger Größe zu unterstützen. Beispiel für BLOBs (TransBase) create table employee ( id integer name char(*), // varchar(4096) picture blob, signature blob, primary key(id) ) Datenbankoperationen auf BLOBs: – Einfügen, Löschen, Ersetzen – Test auf null (where picture is not null) – Bestimmung der Größe in Bytes (size of picture) – Selektion des ganzen Blobs oder eines Teilbereichs (picture subrange(1,100), signature subrange(100, size of signature)) Gleichheitstest werden nicht unterstützt, alle BLOBs gelten als verschieden (wichtig für distinct und Gruppierung). Primär- und Sekundär-Indexe können nicht angelegt werden. BLOBs können nicht direkt über die Ad-hoc-Query-Interfaces (UFI, XUFI, TBI) eingelesen und ausgegeben werden. Die Ein- und Ausgabe erfolgt entweder mit Hilfe des proprietären TransBase-Spool-Mechanismuses oder über ESQL (Emdedded SQL = in 3GL-Sprache eingebettet SQL-Code). 73 Draft (2. März 2000) In ESQL fängt jeder SQL-Befehl mit EXEC SQL an und hört mit ; auf. C- (oder C++- oder COBOL- oder sonstige) Variablen, auf die in einem SQL-Statement zugegriffen wird, müssen zunächst in einer DECLARE SECTION definiert werden. In SQL-Statements kann auf derartige Variablen zugegriffen werden, indem man sie mit einem Doppelpunkt versieht. Datei beispiel.c mit ESQL-Befehlen // Definition von Variablen EXEC SQL BEGIN DECLARE SECTION; blobdesc myblob; EXEC SQL END DECLARE SECTION; myblob.mode = FILENAME; myblob.loc.filename = "MeinBild.gif"; EXEC SQL INSERT INTO graphic VALUES (’Bild 1’, :myblob); EXEC SQL UPDATE graphic SET image = :myblob WHERE name = ’Bild 1’; 5.2.2 CD-ROM-Datenbanken Multimediadaten benötigen vor allem eines: Platz. So ist es nicht verwunderlich, dass billiger Speicherplatz ein begehrtes Datenbankmedium ist. Den billigsten Speicherplatz stellt heute immer noch das Magnetband dar. Allerdings sind die Zugriffszeiten – wegen der linearen Suche – meist indiskutabel langsam. So eignen sich Bänder nur für wenige Anwendungsgebiete wie z. B. Video on Demand (ein Film = ein Blob pro Band). Das jeweils gesuchte Band kann h Datenbanken im Terrabytebereich. dabei von Robotern eingelegt werden Ein anderes sehr billiges Speichermedium ist die CD-ROM. Auch hier können viele CD-Roms von einer sogenannten Jukebox verwaltet werden (Platz für mehrere 100 CDs sowie einen oder mehrere CD-Leser). Jede CD-ROM ist dann in einem von drei Zuständen: online: CD-ROM ist im Lesegerät nearline: CD-ROM ist in der Jukebox Draft (2. März 2000) 74 offline: CD-ROM ist außerhalb de Jukebox und wird bei Bedarf vom Operator eingelegt Der Zugriff auf Online-CDs dauert einige Millisekunden, der Zugriff auf Nearline-CDs einige Sekunden und der Zugriffauf Offline-CDs mehrere Minuten (wenn’s gut geht). Um teure Nearline-Zugriffe zu vermeiden, sollten Daten, die häufig gemeinsam benötigt werden, nach Möglichkeit auf einer CD-ROM untergebrachte werden. TransBase bietet beispielsweise die Möglichkeit CD-ROM-Datenbanken zu erstellen: 1. Entwicklung einer Datenbank wie gewohnt. 2. Erzeugung der späteren CD-ROM-Datenbank zunächst auf Festplatte (Testphase). 3. Brennen der CD-ROM. 4. Einrichten der CD-ROM-Datenbank 5. Benutzen der Datenbank mit zweistufigem Cache: Hauptspeicher und Festplatte. Es ist auch möglich, Daten auf der CD-ROM zu „überschreiben“. Dazu werden die neueren Tupel auf der Festplatte abgelegt und die alten Tupel verschattet (auf der Festplatte als ungültig markiert). 5.2.3 RAID (Plattenfarmen) Idee: mehrere (viele) Platten zu einer logische Platte zusammenschalten Vorteile: – Hohe Bandbreite (z. B. für Video on Demand) – Fehlertoleranz durch redundante Speicherung – billig, da billige Platten eingesetzt werden können RAID = Redundant Arrays of Inexpensive Discs RAID level 0: data stripping h Die logischen Sektoren werden über u Platten verteilt u aufeinanderfolgende Sektoren können gleichzeitig gelesen oder geschrieben werden (sofern der Datenbus breitbandig genug ist). 75 Draft (2. März 2000) Platten 1 2 3 4 5 1 1 2 3 4 5 2 6 7 8 9 10 3 . . . 11 . .. 12 . .. 13 . .. 14 . .. 15 . .. Sektoren Level 0 h schneller Zugriff, keine Redundanz RAID level 1: mirrored disks Die Daten werden auf zwei Platten gleichzeitig abgelegt h Level 1 normaler Lese- + Schreibzugriff, hohe Redundanz RAID Level 2-4: data stripping + parity disks Für jeweils u Sektoren werden auf einer oder mehreren Extra-Platten Parity-Informationen zur Restauration von fehlerhaften Daten abgelegt. Platten 1 2 3 4 5 P 1 1 2 3 4 5 P1 2 6 7 8 9 10 P2 3 11 12 13 14 15 P3 . .. . .. . .. . .. . .. . .. . .. Sektoren Level 2-4 h schneller Lesezugriff, langsamer Schreibzugriff (wegen pot“-Parityplatte), Redundanz (nimmt ab mit wachsendem u ; u mirroring) Draft (2. März 2000) 76 „Hots× h RAID Level 5: parity sections interleaved on disks Um die Schreibgeschwindigkeit zu erhöhen, werden die Paritysektoren gleichmäßig über die Platten verteilt. Platten 1 2 3 4 5 6 1 P1 1 2 3 4 5 2 6 P2 7 8 9 10 3 11 12 P3 13 14 15 . .. . .. . .. . .. . .. . .. . .. Sektoren level 5 h schneller Schreib- + Lesezugriff (Schreibzugriff langsamer als Level 0), Redundanz Anmerkung Redundante Speicherung ist bei großen Plattenfarmen (mehrere 1000 Platten) sehr wichtig, da die Mean Time Between Failures (MTBF) sehr gering ist: h MTBF/10.000 Platten = 100 h = 5d MTBF/Platte = 1.000.000 h Das heißt, in großen Plattenfarmen (wie z. B. VoD-Servern wie dem Oracle Media Server mit bis zu 25.000 Video-Streams gleichzeitig) müssen alle Platten regelmäßig im laufenden Betrieb überprüft und gegebenenfalls ersetzt werden können. 5.3 Volltextindexe (Inhaltssuche) TransBase unterstützt die Volltexttextsuche auf Attributen vom Typ char( u ), char(*) (= varchar(4096)) und blob. Für jedes Attribute, das zur Volltextsuche eingesetzt werden soll, muss zunächst ein Volltextindex erzeugt werden. create [positional] fulltext index <name> <options> on <table> (<attribute>) 77 Draft (2. März 2000) – Positionelle Volltextindexe, d. h., Volltextindexe, die zu jedem Wort auch noch die Wortposition abspeichern, sind umfangreicher als einfache Volltextindexe, ermöglichen aber Phrasensuche (siehe unten). – Die Indexerstellung kann durch die Angabe diverser Optionen gesteuert werden: WORDLIST FROM <table w> Nur Wörter aus der Tabelle <table w> indizieren (Lexikon). STOP WORDS FROM <table s> Wörter aus Tabelle <table s> nicht indizieren (z. B. der, die, das, ein, einer ÜBÜBÜ ). CHARMAP FROM <table c> Buchstaben ersetzen (A, B, C ÜBÜBÜ durch a, b, c ÜCÜBÜ ; ä, ö, ü, ß durch ae, oe, ue, ss etc.). Die Tabelle <table c> hat zwei Spalten: char(1) und char(*). DELIMITERS NONALPHANUM DELIMITERS FROM <table d> Standardmäßig werden Wörter durch Whitespaces voneinander getrennt. Das heißt, Sonderzeichen zählen als Buchstaben. Man kann aber auch alle Sonderzeichen (d. h. Zeichen, die keine Zahlen oder Buchstaben sind) als Worttrenner behandeln (DELIMITERS NONALPHANUM). Oder man kann eine eigene Tabelle mit Worttrennsymbolen definieren. Beispiel CREATE POSITIONAL FULLTEXT INDEX abstract ON buch (abstract) Für jeden Volltextindex <f_index> gibt es Pseudotabellen: – FULLTEXT WORDLIST OF <f_index> (word, wno) – FULLTEXT STOPWORDS OF <f_index> (word) – FULLTEXT CHARMAP OF <f_index> (source, target) – FULLTEXT DELIMITERS OF <f_index> (delimword) Diese können wie normale Tabellen in Select-Statements verwendet werden. Außerdem sind folgende Modifikationen erlaubt: INSERT für WORDLIST und DELETE für STOPWORDS. Dies hat allerdings nur einen Einfluss auf zukünftige Volltextindex-Updates (durch Inserts in die Basistabelle), nicht aber auf den aktuellen Index-Inhalt. Draft (2. März 2000) 78 Wichtiger ist jedoch das Volltextindex selbst. In TransBase gibt es das Spezialprädikat CONTAINS zur (boolschen) Volltextsuche. Beispiele Wortsuche select * from Buch where abstract contains (’database’) Phrasensuche select * from Buch where abstract contains (’database’ ’systems’) Wildcardsuche % und _ haben dieselbe Bedeutung wie im Prädikat LIKE. Nur ist die Suche mit Mitten- und/oder Endtrunkierung (Wasch%, Wasch%en, Wasch%en%) i. Allg. wesentlich effizienter als bei LIKE. Lediglich die Suche mit Anfangstrunkierung (%Lappen) ist langsam (siehe aber unten). select * from Buch where abstract contains (’data%’) Wenn man nach einem %, \ oder _ sucht, muss man \%, \\ bzw. \_ schreiben. Wortabstand select * from Buch where abstract contains (’data%’ [0,3] ’bases’) Hier wird ein Wort beginnend mit data, gefolgt von bis zu drei beliebigen Wörtern, gefolgt vom Wort bases gesucht (zum Beispiel data and knowledge bases). Die Schreibweise contains (’ ÜBÜBÜ ’ [ u ] ’ ÜCÜBÜ ’) ist eine Abkürzung für contains (’ ÜBÜBÜ ’ [0, u ] ’ ÜBÜBÜ ’). Volltextsuche mit Boolschen Operatoren Einzelne Phrasen können mit AND, OR, NOT und Klammerung verknüpft werden. select * from Buch where abstract 79 Draft (2. März 2000) contains ( ’object%’ [1] ’data%’ ’systems’ OR ’distributed’ [1] ’systems’ ) Multivalue-Atome Suche alle Abstracts, die irgendein Wort aus der Tabelle Wortliste enthalten. select * from Buch where abstract contains (ANY (select * from Wortliste)) Nicht-primitive Contains-Atome Das Contains-Prädikat darf auch Attributzugriffe und sogar Subqueries enthalten. Welche Wörter aus der Liste Wortliste kommen in meinen Abstracts vor? select W.Wort form Wortliste W where exists (select * from Buch where abstract contains(W.Wort)) ✎ QaM MNPO$Å~N*ÉÊiÅþÊZ*þÅÉN*ËQaM`ÃÇYQaM9Ä*þÅ~[!¡fÃ\2N¢o£fÇäb­É \2NfÆwþÊ\2N?Ì$ÅSO$ÈIN¥QaM\#e Performanz Die Volltextsuche ist i. Allg. sehr schnell (Ausnahme: Anfangstrunkierung). Das Einfügen neuer Tupel in eine Tabelle mit Volltextindex kann schnell erfolgen. Allerdings wird für die Erzeugung eines ganzen Indexes viel Platz benötigt. Je mehr temporärer Speicher zur Verfügung steht desto besser. Man kann den temporären Speicherplatz bei der Erzeugung des Indexes angeben: SCRATCH 60 MB. Das Löschen ist dagegen sehr langsam ( AÕ`u Ö , wobei u die Größe des Indexes ist). Es ist besser, viele Tupel auf einmal zu löschen als einzeln hintereinander. Tips und Tricks Eine gute Volltextsuche sollte unabhängig von Groß- und Kleinschreibung und spezieller Schreibung der Umlaute funktionieren. Das heißt, man sollte eine charmap der folgenden Bauart anlegen: source A B C ¦$¦$¦ target a b c Draft (2. März 2000) 80 Ä Ö Ü ä ö ü ß ae oe ue ae oe ue ss Diese Charmap wird sowohl bei der Indexerstellung als auch bei der Auswertung von Anfragen verwendet. Das heißt, z. B. die Anfrage ¦$¦!¦ contains (’Mädchen’) ist gleichwertig zur Anfrage ¦$¦$¦ contains (’maedchen’). Manchmal ist es allerdings wichtig, noch wesentlich fehlertoleranter zu arbeiten. Folgendes Verfahren funktioniert immer: Es gebe eine Abbildung §©¨ Wort ª Wort, die jedes Wort in ein anderes Wort transformiert (z. B. § charmap « ’Mädchen’ ¬Y­ ’maedchen’) 1. Bei der Erstellung des Volltextindexes wird jedes Wort mittels § miert, bevor es gespeichert wird. transfor- 2. Jedes Wort einer Anfrage wird ebenfalls mittels § transformiert. Beispiel Mehrere phonetisch ähnlich klingende Laute können durch einen Laut ersetzt und stumme Laute entfernt werden. source ’f’ ’F’ ’p’ ’P’ ’c’ ’h’ ’z’ . . . target ’ph’ ’ph’ ’b’ ’b’ ’k’ ” ’s’ In diesem Fall werden auch fehlerhafte Schreibwesen in einer Anfrage akzeptiert: Haubtbanhof, Fotograph. Allerdings werden auch mehr Fehltreffer gefunden. Die Frage nach Haus liefert auch das Wörtchen aus (außer man läßt nur das klein geschriebene h entfallen). Man kann noch viel weiter gehen: Buchstabenverdopplungen werden entfernt, ie wird durch i ersetzt, ck durch k, tz durch z, dt durch t, etc. Leider wird 81 Draft (2. März 2000) dies von TransBase nicht mehr unterstützt, da die Charmap-Source immer nur aus einem Zeichen bestehen kann. Man kann sich aber dennoch helfen, wenn man eine C- oder C++-Routine hat, die diese Transformationen vornehmen kann. 1. Wende die Routine auf alle Texte an, die volltextindiziert werden sollen und speichere die transformierten Texte (evtl. zusätzlich zu den Orginaltexten) in einer Tabelle ab: create table Text Id integer Text blob, Transformtext blob . . . ); 2. Erzeuge einen Volltextindex auf den transformierten Texten. 3. Jede Benutzerangabe wird mit Hilfe der C/C++-Routine (oder einer Javascript-Routine etc.) transformiert, bevor sie an die Datenbank wietergeleitet wird (Dynamic ESQL). 4. Optional: Jedes Wort eines Treffertextes wird wiederum mit der obigen Routine transformiert (allerdings nur temporär). Jedes Wort, dessen transformierte Form der transformierten Anfrage genügt, wird als Treffer markiert (z. B. in HTML farbig hervorgehoben). Beispiel Text 1: Dies kann man lesen Text 2: Diesen Kahn fährt ein Mann Trafo 1: dis kan man lesen Trafo 2: disen kan faert ein man Die Suche erfolgt nun viel fehlertoleranter als bislang. Es werden aber auch viel mehr falsche Dokumente gefunden. Zum Beispiel liefert die Suche nach „Mann“ und „Kahn“ auch Text 1. Weitere Möglichkeiten: alle Vokale weglassen, Wörter durch phonetische Äquivalenzen ersetzen (dazu braucht man ein phonetisches Lexikon, z. B. klingen „bot“ und „Boot“ gleich, nicht aber „kann“ und „Kahn“) etc. Neben den Worttransformationen gibt es auch noch weitere Techniken, um fehlertolerante Volltextsuche zu ermöglichen. Draft (2. März 2000) 82 Eine bekannte Technik besteht darin, die Wörter Texte in Trigramme (oder allegemein n-Gramme) zu zerlegen: Busbahnhof = ® bu, bus, usb, sba, bah, ahn, hno, nof, of ® Anfragen werden ebenfalls in n-Gramme zerlegt. Diejenigen Texte, in denen die meisten der gesuchten n-Gramme vorkommen werden als Treffer angezeigt. Vorteile: – Bcuhstabenverdreher (sic.) können auch noch zu einem Ergebnis führen (nur ein paar n-Gramme sind falsch) – Zusammen- und Getrenntschreibung wird erkannt („Bahnhof für Busse“, gemeinsame Trigramme: bah, ahn, hno, nof, of ® , bus) Nachteile: – kleine n-Gramme liefern viele Fehler (Jedes Treffer-n-Gramm kann in einem anderen Wort vorkommen.) – große n-Gramme sind nicht sehr fehlertolerant Fazit: Je fehlertoleranter eine Volltextsuche ist, desto mehr Fehltreffer liefert eine Suche. Ein weiteres Problem, die effiziente Suche mit Anfangstrunkierung, kann man relativ einfach lösen. In TransBase wird jedem Wort ein Identifikator zugeordnet: Wort faehrt gehen gehoben geht wolfgang Id 1 2 5 4 3 Die eigentliche Suche erfolgt mit den entsprechenden Identifikatoren, das heißt, jedes Wort einer Anfrage wird durch den zugehörigen Identifikator ersetzt. Endtrunkierung kann sehr effizient abgearbeitet werden, wenn diese Liste alphabetisch geordnet ist, d. h., wenn Wort als Primärschlüssel gewählt wurde. Man muss nur das erste Wort in der Wortliste suchen, das mit dem gesuchten Teilwort beginnt und dann der Reihe nach alle nachfolgenden Wörter mit demselben Anfang ebenfalls in die Suche einbeziehen (geh% ª Wörter 2, 5, 4). Bei der Anfangstrunkierung bleibt einem zunächst nichts weiter übrig, als die ganze Wortliste zu durchsuchen (%t ª 1 ¯ 4). Der Trick ist nun, die Liste zu erweitern, indem man jedes Wort noch einmal rückwärts geschrieben und geeignet markiert mit demselben Identifikator wie das Ursprungswort in die Liste einfügt. 83 Draft (2. März 2000) Wort @gnagflow @neboheg @neheg @theg @trheaf faehrt gehen gehoben geht wolfgang Id 3 5 2 4 1 1 2 5 4 3 Wenn man jetzt die Anfrage %t (natürlich automatisch) durch @t% ersetzt, bekommt man die gesuchte Wortindexliste (4, 1) ganz schnell. Die einzigen Anfragen, die jetzt noch Schwierigkeiten machen, sind Anfragen mit Anfang und Endtrunkierung: %ab% etc. oder gar % (ganz übel)2. Weitere Volltexttechniken Thesauri Ein Thesaurus ist ein Synonymwörterbuch, das in einer Datenbank abgelegt wurde. Insbesondere können fachspezifische Thesauri angelegt werden, die Fachwörtersynonymen aus mehreren Sprachen enthalten. Mathematik: Körper field (nicht etwa: body) Verband lattice (nicht etwa: bandage) Halbachse Ellipsenhalbachse semi axis Bei der Thesaurussuche werden automatisch Synonyma berücksichtigt. Aber auch Thesauri sind nicht gegen Fehltreffer gefeit. Wie soll ein Thesaurus entscheiden, ob mit Körper der medizinische Körper body oder der mathematische Körper field gemeint ist. Stammbildung Einige Volltextsysteme reduzieren Suchwörter und Volltextindexe auf Wortstämme, d. h. sie benutzen die Abbildung § Wortstamm ¨ Wort ª Wort. geht, ging, gegangen, gehend ¦!¦$¦ ª gehen Datenbank, Datenbanken ª Datenbank Haus, Häuser, Hauses ª Haus 2 In OMNIS wird diese Anfrage als unsinnig herausgefiltert. Das heißt aber nicht, dass man OMNIS nicht doch lahm legen kann: %a% oder sogar %% werden abgearbeitet, führen aber zu riesigen Ergebnissen. Draft (2. März 2000) 84 Die Wortstammbildung ist allerdings nicht trivial und vor allem sprachabhängig. Zum Beispiel ist nicht klar, welchen Stamm das Wort „Essen“ hat: „Essen“ (Stadt in Deutschland), „essen“ (Substantivierung) oder „Esse“ (Pluralbildung). WAIS WAIS (Wide-Area Information Systems, pronounced ways) ist ein Volltext-Indizien- und Retrievalsystem, allerdings kein Datenbanksystem (Warum?). WAIS basiert auf dem ANSI-Standard Z39.50 „Information Retrieval Service und Protocol“ aus dem Jahr 1988. WAIS besteht aus zwei Hauptkomponenten: – Eine indexing engine, die für ein Textarchiv (oft fälschlicherweise schon Datenbank genannt) einen Volltextindex erzeugt. – Eine query engine, um Ad-hoc-Volltextanfragen auszuwerten Für zugängliche WAIS-Implementierungen sind beispielsweise: – freeWAIS (heute ZDist) – freeWAISsf Die indexing engine von freeWAIS heißt waisindex. Neuen Index anlegen: waisindex -export -d <Name Indexdatei> -T TEXT *.txt waisindex -export -d <Name Indexdatei> -T PS *.ps Index erweitern: waisindex -a -d <Name Indexdatei> -T TEXT *.txt WAIS-Anfragen können auf verschiedene Arten erfolgen: mittels waisq, waissearch, Perlinterfaces zu diesen Programmen etc. waissearch -d <Name Indexdatei> <Wort>+ Das Programm waissearch kann auch Anfragen an Remote-Datenbanken schicken, wenn diese dem Z39.50-Protokoll genügen. Dazu muss man den Rechner, den Z39.50-Port (Default 210) sowie die Remote-Datenbank kennen. Anmerkung Es gibt weitere Volltext-Engines (die evtl. nicht dem Z39.50-Standard genügen): Glimpse, Harvest etc. 85 Draft (2. März 2000) Fazit Das Ziel jeder Volltextmaschine ist es, Anfragen vollständig und korrekt zu beantworten. Das heißt: recall ­ ° relevant objects returned| ° relevant objects in DB| ± precision ­ ° ² relevant objects returned| ° ° all objects returned ± (es gilt immer ³ 1) ² (es gilt immer ³ 1) Leider sinkt bei heutigen Systemen fast immer die precision mit wachsendem recall. Da heißt, obwohl es viele Volltextsuchtechniken gibt, sind hochwertige Antworten häufig noch die Ausnahme. 5.4 Hypermedia (navigierende Suche) Ein Link hat die Aufgabe, mehrere Dokumente (d. h. Texte oder andere Multimedia-Objekte) oder Teildokumente in Beziehung zueinander zu setzen. Man unterscheidet zwischen: 1. Richtung der Links – unidirektionale Links, die in eine Richtung von Linkquelle zu Linkziel verfolgt werden können (z. B. WWW) – bidirektionale Links, die in beide Richtungen verfolgt werden können 2. Granularität der Links – Node-to-Node-Links: Linkquelle und Linkziel sind vollständige Dokumente (in HTML vorgesehen, von den meisten Browsern aber nicht unterstützt) Draft (2. März 2000) 86 – Span-to-Node-Links: Linkquelle ist ein Teildokument, Linkziel ein vollständiges Dokument (z. B. WWW) – Node-to-Span-Links: Linkquelle ist ein vollständiges Dokument, Linkziel ein Teildokument (in der Praxis sehr selten) – Span-to-Span-Links: Linkquelle und Linkziel sind Teildokumente (in WWW eingeschränkt vorhanden; HTML-Links können auf Tags innerhalb eines Dokuments zeigen; angezeigt wird allerdings immer das gesamte Dokument via Scrollbar) 3. Kardinalität der Links – 1:1-Links: klassisch, z. B. WWW – 1:n-Links: von einer Quelle aus können mehrere Ziele erreicht werden 87 Draft (2. März 2000) – n:1-Links: von mehreren Quellen aus kann ein Ziel erreicht werden – m:n-Links: von mehreren Quellen aus können mehrere Ziele erreicht werden (auch MSMD-Links genannt: Multi-Source-Multi-DestinationLinks) 4. Lokalität der Links – Inter-Dokument-Link Draft (2. März 2000) 88 – Intra-Dokument-Link – – – – Inter-Domain-Links (Domain = Rechner, Lan etc.) Intra-Domain-Links absolute Links relative Links Man beachte, dass alle Kombinationen aller Linkarten möglich sind: bidirektionale Span-To-Node-m:n-Links etc. Bei 1:n- und m:n-Links sind sogar noch zusätzliche Span- und Nodevarianten denkbar. Allerdings machen nicht alle möglichen Links einen Sinn (wie z. B. Intra-Node-to-Node-Links). Links können außerdem benannt sein und beliebige andere Attribute enthalten, wie z. B. ein Attribut Relevanz, das einen Wert zwischen unrelevant (=0) und sehr relevant (1) annehmen kann. Links können außerdem zusätzliche Attribute (wie z. B. Häufigkeit) und/oder Rollennamen an den jeweiligen Linkenden enthalten. Auto 0-1 Bestandteil 3-4 Rad hat Bestandteil ist Bestandteil von Die möglichen Eigenschaften von Links verallgemeinern die bereits bekannten Eigenschaften von ER- oder objektorientierten Modellen. Und tatsächlich können Links in RDBS ebenso wie Relationships als Attribute oder durch eigene Tabellen realisiert werden: m:n-Links mit zusätzlichen Attributen werden durch separate Tabellen realisiert, unidirektionale 1:1-Links können dagegen als zusätzliche Attribute in der Tabelle der Quellenobjekte realisiert werden, wenn die Anzahl der möglichen unidirketionalen Links, die von einem Objekt ausgehen können, beschränkt ist (ansonsten benötigt man ebenfalls eine eigene Linktabelle). Span-Links können entweder – wie in HTML – in die Dokumente selbst eingefügt oder durch spezielle Positionsattribute realisiert werden: z. B. linkStartPos 89 Draft (2. März 2000) und LinkEndePos. Die zweite Technik hat den Vorteil, dass man Teildokumentenicht nur von Textdokumenten, sondern von beliebigen Multimedia-Dokumenten als Linkquelle und/oder Linkziel einsetzen kann: Teilvideo- oder Teilaudio-Sequenzen, clickable images etc. Man beachte: Es ist in HTML zwar nicht vorgesehen, dass sich mehrere Span-Links überlappen, aber dennoch ist dies – zumindest in anderen Hypermedia-Systemen – ohne Weiteres vorstellbar. Links können nicht nur in Tabellen gespeichert, sondern auch berechnet werden (z. B. via JavaScript, Java und Forms). So wäre es z. B. möglich, neue (implizit vorhandene Links) Links über mehrere Dokumente hinweg zu ermitteln. statischer Link statischer Link aus statischen Links berechneter Link 5.4.1 Das Dexter-Referenz-Modell 1988 wurde im Dexter Inn, New Hampshire, USA das sogenannte Dexter Hypertext Referenz Modell entwickelt. Teilnehmer waren Entwickler verschiedener Hypertextsysteme und verwandter Produkte, wie Intermedia, NoteCards, KMS etc. Ziele – Standardterminologie – Referenzmodell zur formalisierten Beschreibung bestehender HypertextSysteme – Basis für die Entwicklung von Austauschformaten Die Ergebnisse waren nicht nur auf Hypertext-, sondern sogar auf beliebig Hypermedia-Systeme anwendbar. Im Dextermodell werden drei Schichten unterschieden: 1. Runtime Layer Präsentationstools, Benutzer-Interaktion 2. Storage Layer enthält das Netzwerk aus Dokumenten und Links Draft (2. März 2000) 90 3. Within-Component Layer enthält die Datenstrukturen und Inhalte der Dokumente Der Within-Component Layer wird im Dexter-Modell nicht genauer spezifiziert, das Hauptaugenmerk liegt auf dem Storage Layer, d. h. dem eigentlichen Netzwerk. Im Dexter-Modell sind Links eigenständige Objekte, die eine Liste von Specifiern enthalten: Jeder Specifier beschreibt einen Linkpfeil: UID Dokumentidentifikator AID Anchoridentifikator im Dokument (jeder Anchor beschreibt ein Subdokument) Direction Flag, mit 4 möglichen Werten: FROM, TO, BIDIRECT, NONE presentation specification (optional) Information über Präsentationsart (für Runtime Layer) Mit der Presentation Specification kann z. B. angegeben werden, ob eine Animation abgespielt werden (z. B. student link) oder mit einem passenden Programm bearbeitet, d. h. editiert (z. B. teacher link) werden soll. Dokumente sind entweder primitiv (sogenannte atoms) oder zusammengesetzte aus anderen Dokumenten (composite objects). Atom #275 Link #222 Composite #174 Component_Info Attr1 ... Attrn PresentationSpec Anchors AID #1 Value AID #2 Value Component_Info Attr1 ... Attrn PresentationSpec Anchors Component_Info Attr1 ... Attrn PresentationSpec Anchors AID #1 Value Content Specifier Content UID #275 AID #2 Direction From PresentationSpec... Atom #379 Atom #862 AID #1 Specifier UID #174 AID #1 Direction To PresentationSpec... Specifier .. . 91 Draft (2. März 2000) Vorteile des Dexter-Modells: – 1:n-, m:n-Links – bidirektionale Links – zusammengesetzte Objekte – sehr mächtige Resolvefunktionen zur Linkverfolgung (boolsche Operationen etc.; Ergebnis ist Anchormenge) – keine dangling references (ein Link der weg ist, ist weg – in allen Dokumenten!) Nachteile des Dexter-Modells: – Links auf Links sind erlaubt (absichtlich) – die Linkrichtung steht nur im Link, nicht aber im Anchor – keine Synchronisation von zeitkritischen Medien (Videos, Audio) – der Within Component Layer wurde nicht spezifiziert (medienabhängige Datenmodelle fehlen) Zwei Fragen an die Studenten: 1. Was kann man mit derartig mächtigen Links alles anstellen? 2. Wie realisiert man soetwas in einer Datenbank? ✎ ´¶µR·a¸· ¹º»¼!½2·¾¿PÀ¥·ÁµRÂa¾¸·a¾Ã¿¥º¸ÄÅ¾ÃÆRµRÂa¾¤À¥·a¸Ç¥ÃIÈYÂa¾·a»É}ʺ¹º»¼!½ÌË;¿PÀW· µRÂS¾ÁÎ~µ ½Ï¥·a»Ð!½2ºÏW·S»½2·a»·aµR»´o¿½2·a»Î~ÈYÏ¥·aÆRÆ·a»½ÑÒµRÂw¼·aÆ ½)É 5.5 Koppelung WWW Ó MMDBS Es gibt mehrere Möglichkeiten, über WWW mit einem (MM)DB-System zu kommunizieren: 1. Via HTTP/CGI (Spezial-CGI-Programme wie PHP/FI oder Spezialserver wie Oracle Web Server oder ÔÕ Web Server) 2. Direkt via HTTP mit Spezial-HTTP-Server 3. Direkt via Java (Spezialschnittstelle oder JDBC) 4. Via ActiveX o. ä. Draft (2. März 2000) 92 benutzerdefinierte HTTP-Ein-/AusgabeFilter (z.B. ISAPI) InternetVerbindung HTTP statische HTML-/ MMDokumente HTTPServer TCP/IP SSI Programmstart WWW-Client HTML-Interpreter JavaScript dynamisch erzeugte HTML-Seiten JScript/VBScript Java (JDBC) ActiveX statische HTMLMasken (server parsed HTML) CGISkript/Programm (PHP/FI,...) Verbindungsaufbau dauerhafte Verbindungen Verbindungsaufbau TCP/IP (Datenbank-) Dämon ... MMDBS MMDBS ad 1: Der wesentliche Nachteil dieser Lösung ist, dass für jeden DB-Zugriff ein eigener CGI-Prozess gestartet werden muss. ad 2: Das Problem der separaten CGI-Prozesse kann abgemildert werden, wenn der aktuelle HTTP-Dämon direkt mit der gewünschten DB in Verbindung treten kann. Allerdings bleibt das Problem bestehen, dass jeder Zugriff nicht direkt, sondern über einen separaten Prozess – einen speziellen HTTP-Dämon – erfolgen muss. ad 3: Den (vielfachen) Umweg über einen HTTP-Dämon kann man sich sparen, wenn die Clients per Java direkt in Kontakt mit der gewünschten Datenbank treten. In diesem Fall ist es möglich, dauerhafte Verbindungen für vollständige Datenbanksitzungen zu etablieren. ad 4: Dies ist eine proprietäre Microsoft-Lösung, die im wesentlichen der Lösung Nr. 3 entspricht. Im Falle der Lösungen 1 und 2 gibt es fast immer einen oder mehrere Datenbankdämone, die eine dauerhafte Verbindung zu den gewünschten Datenbanken unterhalten. Damit wird vermieden, dass für jeden DB-Zugriff zunächst ein zeitauf93 Draft (2. März 2000) wendiger DB-Login-Vorgang durchlaufen werden muss. Statt dessen loggt sich jeder DB-Dämon lediglich ein einziges Mal in den gewünschten Datenbanken ein und reicht anschließend alle Requests unter dieser Kennung an die Datenbanken weiter. Der Nachteil dieser Lösung ist, dass nun der DB-Dämon, nicht mehr aber das DBS selbst für die Benutzerverwaltung (Passwortschutz, Schreib- und Leserechtverwaltung etc.) zuständig ist. Lediglich unter Java ist es möglich auf einen DB-Dämon mit speziellem Dummy-User zu verzichten, da dauerhafte Datenbankverbindungen aufgebaut werden können. 5.5.1 JDBC JDBC (Java DataBase Connectivity) ist eine standardisierte Schnittestelle, um von Java-Programmen aus (insbesondere von Java-Applets aus) mit einer oder mehreren Datenbanken zu kommunizieren. JDBC unterstützt den Verbindungsaufbau, die Übermittlung von SQL-Statements und die schrittweise Abarbeitung von Anfrageergebnissen. Ein großes Problem von JDBC ist direkte Übermittlung von SQL-Befehlen an die jeweilige Datenbank. Da sich der SQL-Sprachumfang von DBS zu DBS unterscheidet, können JDBC-Programme normalerweise nicht problemlos von einem DBS auf ein anderes umgestellt werden. JDBC versucht dieses Problem mittels sogenannter SQL-Escapes abzumildern.3 Zum Beispiel kann man Datumstrings in der Form {d ’1998-09-13’} schreiben. Der jeweilige JDBC-Datenbanktreiber setzt diese Schreibweise in die (normalerweise nicht SQL2-konforme) Schreibweise der zugehörigen Datenbank um. Die meisten der SQL-Escapes vermindern allerdings die Portabilität anstatt sie zu erhöhen, da von den DB-Herstellern nicht verlangt wird, dass sie alle SQL-Escapes einheitlich unterstützen. Um das Portabilitätsproblem zumindest ein wenig in den Griff zu bekommen, fordert SUN von den Datenbankherstellern, dass ihre DBS mindestens den SQL2 Entry Level unterstützen. Nur mit dieser „Mindestausstattung“ kann der SUNKonformitätstest mit Erfolg absolviert werden und der JDBC-Treiber das Gütesiegel „JDBC compliant“ erhalten. Allerdings gibt es auch Treiber ohne dieses Siegel (z. B. für PostgreSQL). Einen weiteren Schritt zu mehr Portabilität stellen die (sehr vielen) verschiedenen boolsche Methoden dar, die eine Auskunft über die Fähigkeiten des aktuellen DB-Systems geben: supportsANSI92EntryLevelSQL() 3 Idee und Syntax stammen von ODBC (Open Database Connectivity) von Microsoft. Draft (2. März 2000) 94 supportsSubqueriesInComparisons() JDBC-Treiber Es gibt verschiedene Arten von JDBC-Treiber: 1. datenbankspezifische Java-Erweiterungen von datenbankspezifischen C/C++/ ¦$¦!¦ -Treibern (< 100 % Java, plattformabhängig, DB-abhängig) 2. datenbankunspezifische Java-Erweiterungen von ODBC-Treibern, sogenannte JDBC-ODBC-Bridges (< 100 % Java, plattformabhängig, relativ DB-unabhängig) 3. datenbankspezifische Java-Treiber (100 % Java, plattformunabhängig, DBabhängig) 4. datenbankunspezifische Java-Treiber von Drittherstellern plus sogenannte Middleware (100 % Java, plattformunabhängig; die Middleware selbst muss nicht in Java geschrieben sein – in diesem Fall läuft die Middleware auf speziellen Plattformen). Java-Anwendung JDBC-Schnittstelle Java JDBCTreiber System A Java JDBCODBCBridge C/C++ Treiber System A ODBCTreiber System B DBS A DBS B Java JDBCTreiber System C Java JDBCTreiber Middleware Middleware DBS C DBS D ad 1: Diese Lösung kann vom Datenbankhersteller schnell implementiert werden, ist allerdings nicht plattformunabhängig. ad 2: Diese Lösung kann von Drittanbietern schnell implementiert werden, ist aber nur eingeschränkt plattformunabhängig (abhängig von der Verfügbarkeit von ODBC-Treibern für viele Plattformen). ad 3: Die Implementierung ist für den Datenbankhersteller aufwendiger. Allerdings ist der Treiber plattformunabhängig. 95 Draft (2. März 2000) ad 4: Die Implementierung ist für Drittanbieter sehr aufwendig (wenn nicht auf vorhandene Schnittstellen zurückgegriffen werden kann). Der Treiber selbst ist plattformunabhängig, die Middleware dagegen meist plattformabhängig. Ein Vertreter dieser Lösung stammt von OpenLink Software Ltd. Openlink bietet nach oben hin sowohl einen JDBC- als auch einen ODBC-Treiber an. Auf der Datenbankseite werden mindestens folgende DBS unterstützt: Oracle, Informix, CA Ingres, Sybase, Progress, Microsoft SQLServer, Unify, DB2, Solid und PostgreSQL. Im Internet ist eine Vollversion mit Beschränkung auf zwei Benutzer gleichzeitig kostenlos erhältlich. Servlets Javaprogramme mit JDBC-Kopplung können nicht nur auf Clients laufen (sogenannte Applets), sondern auch auf Servern (sogenannte Servlets). Vorteile von Servlets: 1. quasi-standardisierter DB-Zugriff (JDBC) 2. plattformunabhängig (modulo JDBC) Allerdings muss der Server fähig sein Servlets auszuführen: 1. Server, die in Java implementiert wurden (Jeeves von Sun, Jigsaw von W3C). 2. Microsoft IIS bindet die Java Virtual Machine (JVM) von Sun ein (und nicht etwa die vom Explorer!). 3. Für den Apache gibt es ein CGI-Programm (einen sogenannten CGI-Wrapper), der für jeden DB-Request die JVM von Sun startet. Eine bessere Lösung gibt es alleridngs schon als Alpha-Release: Der Apache-Server startet einen einzigen JVM-Prozess und lässt alle Servlets darin ablaufen. Eine einfache JDBC-Anwendung Im Wesentlichen muss jedes JDBC-Programm folgende Anweisungen ausführen: <Laden eines JDBC-Treibers> <Öffnen einer Datenbank> While (!<Ende>) { <Senden einer SQL-Anweisung> <Auslesen und Bearbeiten der Ergebnisse> } <Datenbank schließen> Draft (2. März 2000) 96 package mysqltest import java.sql.*; class Test { public static void main() throws java.lang.ClassNotFoundException, java.sql.SQLException { // Einen oder mehrere JDBC-Treiber dynamisch, d. h. zur Laufzeit laden: Class.forName("openlink.jdbc.Driver"); Class.forName("sun.jdbc.odbc.JdbcOdbcDriver"); // Eine Datenbankverbindung aufbauen // (der passende Treiber wird automatisch ermittelt): Connection con = DriverManager.getConnection ("jdbc:openlink://localhost/plz/DSN=dsn_postgres", // "jdbc:odbc://whitehouse.gov:5000/Cat;PWD=Socks", // "jdbc:odbc:corejava", "Wolfgang",// username "geheim", // password ); // Nun kann für diese Verbindung ein Statement erzeugt werden: Statement stmt = con.createStatement(); // SQL-Anfragen werden über Statementobjekte an die Datenbank geschickt; // das Ergebnis dieser Anfragen sind Ergebnisobjekte: ResultSet rs = stmt.executeQuery ("select * from Lieferant L" + "where L.Name = ’Maier’" ); ResultSetMetaData rsmd = rs.getMetaData(); // Nun kann das Anfrageergebnis verarbeitet werden: // Als Ergebnis wird ein HTML-Dokument ausgegeben. // Das heißt, dieses Programm könnte als Servlet laufen. System.out.println ("<!DOCTYPE HTML PUBLIC ¦$¦!¦ >"); System.out.println ("<HTML>"); ¦$¦$¦ 97 Draft (2. März 2000) System.out.println ("<TABLE>"); // Die Tabellenausgabe fängt mit dem Spaltennamen an // (bei den Spaltennamen handelt es sich um "Metadaten"): System.out.println ("<TR>"); for (int i=1; i<=rsmd.getColumCount(); i++) system.out.println ("<TH>"+rsmd.getColumnName(i)+"</TH>"); System.out.println ("</TR>"); // Nun können die Ergebnistupel ausgegeben werden: while (rs.next()) // Solange noch ein Tupel da ist { // (funktioniert auch bei leeren Ergebnissen) System.out.println ("<TR>"); for (int i=1; i<=rsmd.getColumnCount(); i++) System.out.println("<TD>"+rs.getObject(i)+"</TD>"); // rs.getObject(getColumnName(i)) funktioniert auch System.out.println ("</TR>") } // Die Tabelle ist fertig: System.out.println ("</TABLE>"); // Nun heißt es aufräumen // (man könnte diese Arbeit auch dem garbage Collector überlassen): rs.close(); // Ergebnis-Cursor schließen stmt.close(); // Statement schließen con.close(); // Datenbankverbindung schließen }; }; Draft (2. März 2000) 98 Kapitel 6 Objektorientierte Datenbanken OODBS bieten viele objektorientierte features: – Objektidentifikatoren – Vererbung – Methoden – Kapselung – etc. Insbesondere ist einer der wesentlichen Einschränkungen von RDBS in OODBS aufgehoben worden: Tabellen müssen nicht mehr in 1NF vorliegen. Derzeit gibt es zwei wesentliche Bemühungen, OODBS zu standardisieren: – SQL3, ein ISO/ANSI-Standard – ODMG, ein Industriestandard (kein offizieller Standard) Für die Praxis derzeit wichtiger ist allerdings der ODMG-Standard, da er von einigen DB-Herstellern bereits rudimentär unterstützt wird. SQL3-fähige DB-Systeme werden wohl noch einige Zeit auf sich warten lassen. Derzeit sind die DB-Hersteller vollauf damit beschäftigt SQL2-(full level)-DB-Systeme zu implementieren. 6.1 ODMG ODMG (Object Database Management Group) ist eine Untergruppe der OMG (Object Management Group). In der OMG sind 500 Institutionen und Firmen vertreten. Ziel der OMG ist es, eine Referenzarchitektur für verteilte Objektsysteme zu schaffen. 99 Draft (2. März 2000) Mehrere Hersteller von OODBS (wie O2, Objectivity, ONTOS, Versant etc.) haben sich Anfang der 90er in der ODMG zusammengeschlossen um kurzfristig einen Standardisierungsvorschlag für OODBS zu erarbeiten. 1993: Standardisierungsvorschlag ODMG-93, Version 1.0 1994: Standardisierungsvorschlag ODMG-93, Version 1.1 1995: Standardisierungsvorschlag ODMG-93, Version 1.2 1997: Standardisierungsvorschlag ODMG 2.0 Die Vorteile des ODMG-Standards: – kurz, verglichen mit SQL3 (wenige 100 Seiten vs mehrere 1000 Seiten) – es gibt bereits Teilimplementierungen – OQL ist stark an das Select-Statement von SQL angelehnt Die Nachteile des ODMG-Standards: – Er ist inkonsistent, ungenau und unvollständig (da sehr kurz gehalten), oft wird nur die Syntax nicht aber die Semantik beschrieben. – Die neueren Versionen sind nicht abwärtskompatibel (Konzepte werden in neueren Versionen geändert oder entfallen ganz, die Semantik wird geändert etc.). – Die Definition der ODMG-Konformität (ODMG-compliant) ist herstellerfreundlich aber untauglich: Sobald eine von vier (von derzeit fünf) Teilkomponenten in einer OODBS implementiert wurde und der Hersteller dies bei der ODMG meldet, gilt das OODBS als ODMG-konform. Es gibt auch noch das Gütesiegel ODMG-zertifiziert (ODMG-certified), das bislang jedoch noch kein OODBS erhalten hat. ODMG 2.0 besteht aus folgenden Komponenten: – ODL (Object Definition Language, analog zu DDL) – OQL (Object Query Language, select analog zu DML) – C++-Sprachanbindung – Smalltalk-Sprachanbindung – Java-Sprachanbindung (neu, nicht Bestandteil der Konformitäts-Definition) Achtung: OQL ist immer noch nicht berechnungsvollständig (keine rekursiven Views, kein While o. ä.). ODMG 2.0 unterstützt: Draft (2. März 2000) 100 Objekte, Werte (Literale genannt), Klassen (Typen genannt) mit und ohne Extension, Attribute, Methoden (Operationen genannt), Beziehungen, Vererbung (ISA-Hierarchien ohne Mehrfachvererbung und Implementierungshierarchien mit Mehrfachvererbung). Der Nullwert heißt in ODMG nil. Die Semantik entspricht der Nullwertsemantik von SQL2. Allerdings ist es nicht möglich, einen Datentyp als not null zu deklarieren. 6.1.1 Primitive Datentypen ODMG unterstützt die üblich primitiven Datentypen: – Float, Boolean, String, Enum etc. Außerdem unterstützt ODMG in Anlehnung an SQL2 folgende Datentypen: – Date, Interval, Time, Timestamp 6.1.2 Komplexe Datentypen ODMG unterstützt folgende komplexe Datentypen (wobei t ein beliebiger Datentype sei): Set<t> mengenwertige Objekte Bag<t> multimengenwertige Objekte List<t> listenwertige Objekte, insbesondere String und Bit_String Array<t> ähnlich wie List<t>, allerdings kann es leere Feldelemente geben, d. h. Feldelemente deren Wert gleich Nil ist und die die Bedingung is_defined( ¦$¦$¦ ) erfüllen Dictionary<k,t> Assoziatives Array mit Schlüsseltyp k Diese Datentypen liefern Objekte als Ergebnis, d. h. eine Menge, ein Bag, eine Liste etc. ist ein Objekt. Für diese Objekte gibt es eine Reihe von Methoden: cardinality() Anzahl enthaltener Elemente is_empty() Test: Container ist leer contains_element() Test: Element enthalten insert_element() Element einfügen 101 Draft (2. März 2000) remove_element() Element löschen create_iterator() Erzeugt einen Iterator zum Abklappern der einzelnen Elemente (Iteratormethoden: not_done(), reset(), get_element(), advance(), etc.) Für Mengen (set<t>) gibt es noch weitere Methoden: union_with() intersection_with() difference_with() is_subset_of() is_proper_superset_of() Ebenso gibt es für die übrigen Container-Datentypen spezielle Methoden. Denselben Satz an Container-Typen gibt es nochmal als Werttypen, d. h., in diesem Fall sind Mengen, Bags, Listen etc. Werte ohne OIDs. Zusätzlich gibt es den komplexen Werttyp (aber komischerweise nicht den Objekttyp) struct: struct< Ö× ¨ Ø !× ¯ ¦$¦$¦ ¯iÖÙ ¨ Ø Ù > Mit Hilfe dieser Datentypen lassen sich insbesondere Tabellen beschreiben: ¨ Ø J× ¯ ¦!¦$¦ ¯iÖÙ |¨ Ø Ù >> set<struct< Ö× | Diese Tabellen müssen aber nicht 1NF sein: set<struct<Name: string, Telefon: list<string>>>> "Wolfgang" ["325","450"] "Marianne" [] Außerdem gibt es weitere Arten von Tabellen: Tabellen mit Duplikaten bag<struct< ¦!¦$¦ >> geordnete Tabellen list<struct< ¦$¦$¦ >> geordnete Tabellen mit Leerzeilen array<struct< ¦$¦!¦ >>. Die Modifikation von Objekten (und damit auch von Tabellen) erfolgt in ODMG prozedural und nicht etwa deklarativ wie in SQL. Zu diesem Zweck kann man Methoden wie insert_element() einsetzen oder neue Methoden definieren. Operationen werden in der ODL (siehe nächster Abschnitt) deklariert, nicht aber definiert. Die Definition erfolgt in einer Host-Sprache (derzeit entweder C++ oder Java oder Smalltalk), die über eine standardisierte ODMG-Schnittstelle (C++-Bindung, Java-Bindung oder Smalltalk-Bindung) an ein ODMS-Datenbanksystem gekoppelt ist. Draft (2. März 2000) 102 Leider ist es in der ODL nicht möglich Anfrage- und Modifikationsmethoden zu unterscheiden. Das heißt, wenn man eine Methode für ein Objekt aufruft, kann man nie sicher sein, dass sich dadurch das Objekt nicht verändert. Die Operationsparameter werden mit den Schlüsselwörtern in, out, inout markiert, um Input- und/oder Output-Parameter zu definieren. Zum Beispiel: Integer add (in Integer x); 6.1.3 ODL Die wesentliche Aufgabe der Objekt Definition Language (ODL) ist es, Klassen zu definieren. Ein objektorientiertes Datenmodell kann sehr einfach auf eine Menge von Klassendefinitionen abgebildet werden. Das heißt, ODMG-Klassendefinition entsprechen den SQL-Tabellendefinitionen. Allerdings gehört zu jeder SQL-Tabellendefinition automatisch auch eine Datenbanktabelle, in der die zugehörigen Tupel abgelegt werden. Es wird also nicht zwischen Schema und Extension unterschieden. In ODMG kann dagegen für jede Klasse explizit angegeben werden, ob ein geeigneter Container zur Verwaltung der Klassenextension angelegt werden soll oder nicht. Man beachte, dass auch für Klassen ohne Extension Objekte erzeugt werden können. Diese müssen allerdings immer als Bestandteil anderer Objekte gespeichert werden. Dies ist möglich, da ODMG-Objekte nicht in 1NF vorliegen müssen. In ODMG werden zwei Arten von Klassen unterschieden: interfaces und classes. Ein Interface ist wie folgt aufgebaut: interface <Name> [:<Superinterfaces>+] { <Attribute> <Relationships> <Methodendeklarationen (= Operationendeklarationen)> } Ein Interface legt also die üblichen Eigenschaften von Objekten fest. Dabei fällt auf, dass Mehrfachvererbung unterstützt wird und Beziehungen (Relationship) mit Hilfe einer besonderen Art von Attributen und nicht etwa mit Hilfstabellen oder Hilfsklassen (wie in SQL) realisiert werden. Eine Klasse ist wie ein Interface aufgebaut, kann aber noch zusätzlich eine Klassenvererbung, eine (transiente = flüchtige oder persistente = dauerhafte) 103 Draft (2. März 2000) Klassenextension und Schlüsselattribute definieren. Dabei wird seit der Version ODMG 2.0 Klassen-Mehrfachvererbung nicht mehr unterstützt. class <name> [extends <class>] [: <superinterfaces>+] ([extend <Name der Extension>] [key[s] <Schlüsselkandidat>+] )[transient/persistent] { <Attribute> <Relationships> <Methodendeklarationen> } Eine Menge von Interface- und Klassendefinition wird zu einem Modul zusammengefasst. Außerdem können Module Konstantendefinitionen, Typdefinitionen und Ausnahmedefinitionen enthalten. Das Klassenhierarchie Mitarbeiter 0..* hat_Untergebene hat Chef 0,1 hat_Chef kann beispielsweise als folgendes Modul realisiert werden: module Firma { const Stringlaenge = 20; deftype struct TAdresse { string<Stringlaenge> Strasse; ¦$¦$¦ } exception AbteilungGibtEsNicht { string FehlerMeldung; string FalscherName; Draft (2. März 2000) 104 ¦$¦$¦ } interface Person_IF { attribute string Name; attribute string Abteilung; attribute TAdresse Adresse; attribute list<String> Tel; } class Mitarbeiter: Person_If (extent EMitarbeiter key MitarbeiterNr ) { readonly attribute string MitarbeiterNr; relationship Chef hat_Chef inverse Chef::hat_Untergebene; void NeueAbteilung (in string Abteilung) raises AbteilungGibtEsNicht; } class Chef extends Mitarbeiter (extent EChef) { relationship set<Mitarbeiter> hat_Untergebene inverse Mitarbeiter::hat_Chef } } Methoden werden – wie bereits erwähnt – nicht in ODL, sondern in einer Hostsprache implementiert. Dabei können geerbte Methoden – wie NeueAbteilung – natürlich überschrieben werden. So sollte die Methode NeueAbteilung bei Chefs nicht nur das Attribut Abteilung, sondern auch das Attribut hat_Untergebene aktualisieren. Man beachte, dass jede Modifikation des Relationship-Attributs hat_Untergebene auch eine Modifikation der zugehörigen inversen Relationship-Attribute hat_Chef zur Folge hat (und umgekehrt). Wenn beispielsweise hat_Untergebene (z. B. mittels remove_element) geleert wird, muss bei allen betroffenen Mitarbeitern nil als Wert von hat_Chef eingetragen werden. Die neuen Untergebenen eines Chefs 105 Draft (2. März 2000) können anschließend abhand des neuen Abteilungsnamens aus der Extension EMitarbeiter ermittelt werden. Objekterzeugung Für jede Klasse C existiert ein Konstruktor C(<Attr1>:<Wert1> ¦$¦$¦ ). Objekte haben einen eindeutigen OID. Zusätzlich können Ihnen externe Identifikatoren (EIDs) zugewiesen werden. 6.1.4 OQL Neben den speziellen Hostsprachanbindungen (C++-Bindung etc.) unterstützt ODMG auch noch eine sprachunabhängige (Ad-hoc-)Anfragesprache: OQL. Diese Sprache orientiert sich stark an SQL2, ist jedoch viel flexibler, da die Beschränkung auf 1NF entfällt. In OQL gibt es neben Select-Statements, deren Syntax im Wesentlichen eine Erweiterung der SQL2-Syntax darstellt, noch andere Arten von Anfragen (Queries): – Konstanten, wie nil, true, false, 1, 3.14 – Benutzerdefinierte Konstanten – Ausdrücke, wie 3+4, (a+5)*6, (a or b) and not c, 4<=e, a*element(select ¦$¦$¦ from $¦ ¦!¦ where) – Containerkonstruktoren (set(<query>+) etc. ), wie set(1,2,3,3), bag(set(1),set(1),set(1,2)), struct(a: 4, b: set(2,3)) – Funktionsaufrufe, wie fac(6), f(set(1), select ¦$¦$¦ ) – Pfadzugriffe, wie Wolfgang.Adresse.Strasse, Wolfgang.Kinder(3) – Mengenverarbeitung, wie Ú for all <var> in <query>: <query2> Ú exists <var> in <query>: <query2> Ú exists (<query>) Ú unique (<query>) Ú <query> in <query> Ú <query> <|<=| ¦$¦!¦ some|any|all <query> Ú count(<query>), count (*) Ú sum(<query>), min, max, avg Draft (2. März 2000) 106 – Mengenoperationen, wie intersect, union, except, in – Konversionsfunktionen wie listtoset, element (Konvertierung einer einelementige Menge zu ihrem Element, z. B. element(set(3))=3), distinct (Duplikatelemination), flatten (die erste Klammerebene wird entfernt) z. B.: flatten(list(list(1,2),set(3,3,4),bag(3,3))= list(1,2,3,4,3,3) Die Select-Anweisung sehen im Prinzip genauso aus wie in SQL2, mit dem wesentlichen Unterschied, dass in den einzelnen Klauseln beliebige Queries (vom jeweils passenden Typ) stehen dürfen. Der Ergebnistyp eine Selectanweisung ist entweder bag< ¦!¦$¦ > (select ¦$¦$¦ ) oder set< ¦!¦$¦ > (select distinct ¦!¦$¦ ) oder list< ¦$¦$¦ > (select ¦!¦$¦ order by ¦$¦$¦ ) Auch ist es in OQL möglich, Views zu definieren (allerdings wiederum keine rekursiven Views): define <Viewname> as <query> Beispielsanfragen select distinct Name, Tel from Mitarbeiter Ergebnistyp: set<struct<string Name, list<string> Tel>> Ergebnismenge: set(struct(Name: "Wolfgang", Tel: list("325","450")), struct(Name: "Marianne", Tel: list()) ¦$¦$¦ ) Alternative Schreibweise: select distinct struct(Name: m.Name, Tel: m.Tel) from Mitarbeiter as m Weitere Möglichkeiten: select struct(Name: m.Name, Tel: (select * from m.Tel as y where y like "089%") ) from Mitarbeiter as m 107 Draft (2. März 2000) select m.Adresse.Ort from Chef as p, p.hat_Untergebene as m where p.Name="Hinterhuber" An diesem Beispiel sieht man, dass durch die NFNF-Struktur der Klasse Chef, die explizite Angabe eine Joinbedingung nicht mehr notwendig ist. Dies ist einer der Hauptgründe für die Argumentation, dass OODBS wesentlich effizienter als RDBS seien. Allerdings ist das i. Allg. ein Trugschluss. Einerseits kann man in manchen RDBS sogenannte Clusterindexe zum Beschleunigen bestimmter Joinoperation definieren, andererseits kommt man auch in OODBS nicht an expliziten Joins vorbei, wenn Anfragen gestellt werden, die „quer“ zur Objekthierarchie liegen: select struct(Mitarbeiter: m1, Kollege: m2) from Mitarbeiter as m1, Mitarbeiter as m2 where m1.Gehalt < m2.Gehalt Man beachte, dass es auch viele Nicht-Select-Anfragen gibt: (3*4+27)/5 Geschaeftsfuehrer // EID eines Objektes der Klasse Chef Mitarbeiter // Ein mengenwertiges Objekt Geschaeftsfuehrer.Adresse.Strasse.Hausnummer.Stockwerk count(Geschaeftsfuehrer.hat_Untergebene) count(select p from Geschaeftsfuehrer.hat_Untergebene p where p.Adresse.Ort = "Augsburg") Anmerkung: Die SQL2-Schreibweise select count(p) ¦$¦$¦ wird auch unterstützt. for all p in Chef: p.Gehalt>100000 // true oder false Anmerkung 2: OQL unterstützt im Gegensatz zu SQL exists und for all! Man kann auch neue Datentypen definieren und die zugehörigen Konstruktoren in Anfragen einbeziehen. Zum Beispiel: typedef struct KurzAdresse {String Ort}; typedef set<KurzAdresse> Kurzadressen; Kurzadressen(select Kurzadresse(Ort: p.Ort) from Mitarbeiter) Da Funktions- und Methodenaufrufe spezielle Anfragen sind, kann man diese ohne besondere Vorkehrungen ausführen oder in komplexere Anfragen einbauen. Draft (2. März 2000) 108 select p.Alter() from Mitarbeiter p select p.Alter("1998/05/05") from Mitarbeiter p Hier sei Alter() eine Methode, die das Alter eines Mitarbeiters mit Hilfe des aktuellen Datums oder des angegebenen Datums und des Geburtstages des Mitarbeiters berechne. Anmerkung: Über Objektmodifikation und insbesondere die Effekte, die der Aufruf von Updatemethoden in Select-Statements hat, wird im ODMG-Standard nichts gesagt. Updatemöglichkeiten werden nur für die C++-Bindung (C++ OML) beschrieben – auf einer einzigen Seite. Dabei ist es gerade die Semantik von Updateoperationen, die im Falle von deklarativen Sprachen wie SQL und OQL die meisten Probleme verursacht. 109 Draft (2. März 2000) Draft (2. März 2000) 110 Kapitel 7 Normalformtheorie 7.1 Funktionale Abhängigkeit Û « Ü $× ¯ ¦$¦$¦ ¯ Ü Ùs¬ ein Relationenschema Û mit den Attributen $ ¦ $ ¦ ¦ @ ­ Ý × $ ¯ ¯ Ù s Þ . Ü Ü Ü Eine Attributmenge ß6à Ü heißt funktional abhängig (functional dependent) von einer Attributmenge áà Ü , in Zeichen á<ª ß , wenn gleiche Attributwerte für á auch gleiche Attributwerte für ß erzwingen. Es sei Beispiel Liefer Lieferant Adresse Artikel Preis ’Mayer’ ’Königsbrunn’ ’PIII500’ 500 ’Mayer’ ? ’PIII600’ 1200 Wenn die Adresse funktional vom Lieferant abhängt (Lieferant ª Adresse), dann muss der Wert von ? gleich ’Königsbrunn’ sein. Bestimmte funktionale Abhängigkeiten können zu sogenannten Update-Anomalien führen. – Update-Anomalie Die Änderung der Adresse von Mayer muss in jedem Tupel geschehen. – Insert-Anomalie Die Adresse von Mayer kann nicht erfasst werden, wenn Mayer (noch) nichts liefert. – Delete-Anomalie Löscht man das gesamte Liefersortiment von Mayer (z. B. bei einer Produktumstellung), verliert man seine Adresse. Ziel der Normalformtheorie ist es, Anomalien, die durch redundante Speicherung von Fakten entstehen, zu vermeiden. Im Folgenden werden wir uns auf Redundanzen, die sich durch funktionale Abhängigkeiten ergeben beschränken. 111 Draft (2. März 2000) 7.1.1 Reduzierte funktionale Abhängigkeiten Eine funktionale Abhängigkeit á6ª Ö heißt reduziert, wenn 1. Ö ein einzelnes Attribut ist ã 2. Ö â á ( ¦$¦!¦ Öä $¦ ¦$¦ ªåÖsä gilt nämlich immer) 3. Für keine echte Teilmenge á'æç:á gilt á'æª Ö ( Ö heißt in diesem Fall voll funktional abhängig von á ) Jede Menge von funktionalen Abhängigkeiten (kurz FD-Menge) kann in eine äquivalente (gleichwertige) Menge von reduzierten funktionalen Abhängigkeiten (kurz rFD-Menge) umgewandelt werden. Wenn in einer rFD-Menge keine funktionale Abhängigkeit aus anderen berechnet werden kann (wie in Ü ª áè¯á<ª ßêé Ü ª ß ), spricht man von einer minimalen Überdeckung. 7.1.2 Schlüsselkandidaten Eine Menge ëìà Ü von Attributen heißt Schlüsselkandidat von Û , wenn alle Attribute von Û voll funktional von ë abhängig sind. Ein Attribut Ö , das zu keinem Schlüsselkandidaten gehört, heißt Nichtschlüssel-Attribut, alle anderen Attribute heißen Schlüssel-Attribute. 7.2 Normalformen 7.2.1 Erste Normalform (1NF) Im Weiteren nehmen wir an, dass alle Attribute primitive Domänen (wie Bool, Varchar, Integer etc.) anstelle von komplexen Domänen (wie Set, List, Tupel etc.) haben. Wie bereits bekannt ist, spricht man in diesem Fall von erster Normalform (1NF). In RDBS ist diese Bedingung immer erfüllt, in ODBS dagegen nicht. 7.2.2 Zweite Normalform (2NF) Eine rFD-Menge í erfüllt die zweite Normalform (2NF), wenn für alle î6ïñðóò ð î í mit Nichtschlüssel-Attribut gilt, dass ein Schlüsselkandidat ist î oder ein Nichtschlüsselattribut enthält. Das heißt, es gibt kein Nicht-Schlüsselattribut, das voll funktional abhängig von einem echten Teilschlüssel ist. Draft (2. März 2000) 112 Beispiel Das Relationenschema Lieferant Artikel Adresse Preis ï mit Lieferant Adresse ist nicht in 2NF, da Lieferant kein Schlüsselkandidat ist (sondern Lieferant, Artikel), wohl aber ein Schlüsselattribut und da Adresse ein Nicht-Schlüssel-Attribut ist. Die Relationenschemata Lieferant Adresse Lieferant Artikel, Preis Lieferant ï Adresse sind dagegen in 2NF. 7.2.3 Dritte Normalform (3NF) Eine rFD-Menge í erfüllt die dritte Normalform (ist in 3NF), wenn für alle î6ïñðóò ð î í mit Nichtschlüssel-Attribut gilt, dass ein Schlüsselkandidat ist. Diese Normalform ist strenger als 2NF, da Nichtschlüssel-Attribute nur noch von Schlüsselkandidaten abhängen dürfen, nicht mehr aber von Nichtschlüsselkandidaten: 3NF ô 2NF ( ô 1NF) Beispiel Das Relationenschema ï Artikelnr DMPreis EuroPreis 1 2 1,96 1,96 DMPreis ï EuroPreis EuroPreis DMPreis 1,00 1,00 ist nicht in 3NF (wohl aber in 2NF). Die Relationenschemata Artikelnr EuroPreis EuroPreis DMPreis EuroPreis ï DMPreis ï DMPreis EuroPreis oder Artikelnr DMPreis DMPreis Europreis ï DMPreis ï EuroPreis EuroPreis DMPreis sind dagegen alle in 3NF. 113 Draft (2. März 2000) 7.2.4 Boyce-Codd-Normalform (BCNF) Eine rFD-Menge í erfüllt die Boyce-Codd-Normalform (ist in BCNF), wenn für î6ï ðò î alle í gilt, dass ein Schlüsselkandidat ist. Diese Normalform berücksichtigt – im Gegensatz zu 2NF und 3NF – auch Abhängigkeiten zwischen Schlüsselattributen. Es gilt also: BCNF ô 3NF ô 2NF ( ô 1NF) Beispiel Das Relationenschema Stadt Straße Postleitzahl Königsbrunn Blumenallee 86343 ? (Redundanz) Lilienstraße 86343 ï ï Stadt,Straße Postleitzahl, Postleitzahl Stadt ist in 3NF (da es gar keine Nichtschlüsselattribute gibt), aber nicht in BCNF. Grund: Es gibt zwei Schlüsselkandidaten: Stadt, Straße und Straße, Postleitzahl Das Attribut Postleitzahl alleine ist allerdings kein Schlüsselkandidat. Das Relationenschemata Stadt, Straße Straße, Postleitzahl sind in BCNF. Nun können allerdings die funktionalen Abhängigkeiten des Ausgangsschemas nicht mehr gewährleistet werden (außer, wenn beide Tabellen immer gleichzeitig und dann konsistent modifiziert werden). 7.3 Zerlegung (Dekomposition) eines Relationenschemas Ein gegebenes Relationenschema õ kann bzgl.. einer Menge í immer so in Relationenschemata õoö!÷$ø$ø!ø$÷õù zerlegt werden, dass folgendes gilt: 1. õoö!÷$ø$ø!ø$÷õù sind – je nach Wunsch – in 2NF, 3NF oder BCNF 2. Für jede Relation ú , die í erfüllt, gilt újû=üýþ$ÿúø$ø$ø~üýÿ`ú Die zweite Bedingung heißt lossless-join- oder nonadditive-join-Eigenschaft. Sie besagt, das man mit Hilfe von (Natural)joins die ursprüngliche Relation aus den zerlegten Relationen berechnen kann. Draft (2. März 2000) 114 Man beachte, dass diese Bedingung nicht für jede beliebige Zerlegung gilt: õ Mitarbeiter Alter Tel Anton 38 427 Berta 38 305 õoö Mitarbeiter Alter Anton Berta õ Alter Tel 38 38 38 38 427 305 õoö õ Mitarbeiter Alter Tel Anton Anton Berta Berta 38 38 38 38 427 305 427 305 Die angegebene Zerlegung ist nicht möglich, da eine funktionale Abhängigkeit ï Tel nicht existiert. Alter Algorithmus 3NF-Dekomposition Gegeben seien ein Relationenschema õ zusammen mit einer Menge í von funktionalen Abhängigkeiten. Alle Attribute sollten in irgndeiner (wenn auch nicht notwendigerweise funktionalen) Beziehungen zu anderen Attributen stehen. Sollte es Attribute ohne irgendeine Beziehung zueinander geben (wie z. B. Geburtstag, KByte, AnzahlReserveRäder), so sollten õ und í vorher in mehrere Teilschemata aufgespalten werden. 3NF-Dekomposition ( õ ,í ): 1. Erzeuge für jede Abhängigkeit îêï ðèò í das Relationenschema îÍð . 2. Wenn keines der erzeugten Relationenschemata einen vollständigen Schlüsselkandidaten enthält, wähle einen Schlüsselkandidaten aus und füge ihn als eigenes Schema hinzu. 3. Entferne Schemata, die Teil eines anderen Schemas sind. 4. Fasse Relationenschemata mit gleichen Schlüsselkandidaten zu einem Schema zusammen (sofern zwischen den Nicht-Schlüssel-Attributen keine funktionalen Abhängigkeiten bestehen). S A, S B û S A B Algorithmus BCNF-Dekomposition îêïåð die BCNF-Eigenschaft von õ:û*ö!÷$ø$ø$øJ÷où verletzt, zerlege õ in ð õoöPû3õ und Wenn 115 Draft (2. März 2000) õ û îÍð und zerlege die resultierenden Schemata weiter: BCNF-Dekomposition ( õ ö ÷ ) BCNF-Dekomposition ( õ ÷ ) Beispiel V P H R S N Vorlesung Professor Stunde (+ Tag) Raum Student Note ï P V R R N V HR HP HS VS ï ï ï ï Ein Professor pro Vorlesung höchstens eine Vorlesung pro Stunde und Raum Ein Professor kann zur selben Zeit nicht an zwei Orten sein Auch Studenten sind unteilbar Ein Student hat eine Note pro Fach 3NF-Dekomposition VP HRV HPR VSN HSR Schlüsselkandidaten V HR HP VS HS ï ï ï ï ï VP HRVP HPRV VSNP HSRVPN HS ist in HSR bereits enthalten, damit ist das obige Schema das gesuchte 3NFSchema. Es ist nicht ideal, da dies Lossless-join-Dekomposition von R auch mit einigen echten Teilmengen dieses Schemas erreicht wird ( ô Redundanz). Man kann aber auf keine Tabelle verzichten, wenn man alle Abhängigkeiten berücksichtigen will. BCNF-Dekomposition VPHRSN ï V P: V ist kein Schlüsselkandidat VHRSN VP Draft (2. März 2000) 116 ï HR HRSN ï HP ï VS ï HS HRSN V: HRV R: N: R: HRV HR ist kein Schlüsselkandidat VP entfällt entfällt HS ist ein Schlüsselkandidat VP Dies ist ein BCNF-Schema, aber ein schlechtes. Zum Beispiel ist die Note nicht bei der zugehörigen Vorlesung, zwei Abhängigkeiten werden gar nicht mehr beachtet. Beispiel 2 Stadt Straße PLZ ï ï Stadt Straße PLZ, PLZ Stadt 3NF-Dekomposition Stadt Straße PLZ PLZ Stadt Das zweite Schema entfällt, da es Teil des ersten ist. BCNF-Dekomposition ï Stadt, PLZ ist kein Schlüsselkandidat PLZ Stadt Straße PLZ Stadt Fazit Die Zerlegung (Dekomposition) eines Relationenschemas in 3NF-Schemata (und damit auch in 2NF-Schemata) bewahrt alle funktionalen Abhängigkeiten, ist also abhängigkeitserhaltend. BCNF ist dagegen nicht abhängigkeitserhaltend (Integritätsbedingungen fallen weg) vermeidet aber – in seltenen Spezialfällen – mehr Redundanz und damit Updateanomalien. In manchen Fällen verzichtet man aus Effizienzgründen auf vollständige 3NF- oder BCNF-Normalisierung. 7.3.1 weitere Normalformen Funktionale Abhängigkeiten sind nicht die einzigen Abhängigkeiten zwischen Attributen, die zu redundanter Speicherung führen. Es gibt weitere Abhängigkeiten, wie – Mehrwertige Abhängigkeiten ( ô 4NF) 117 Draft (2. März 2000) – Join-Abhängigkeiten ( ô 5NF) – Abhängigkeiten zwischen Relationen (bislang keine Normalformen) – etc. Jede weitere Normalform sollte die bekannten Normalformen verallgemeinern. Es gilt z. B. 5NF ô 4NF ô BCNF ô 2NF ô 1NF Das heißt, jede weitere Normalform zerschlägt ein Relationenschema in immer mehr, kleinere Teilrelationen. Vorteil: Redundanzvermeidung, Anomalienvermeidung Nachteil: Effizienzprobleme durch mehr Joins In der Praxis ist 3NF (und manchmal sogar 2NF) fast immer ausreichend. Schemata, die zwar 3NF, aber nicht BCNF sind, kommen in der Praxis so gut wie nicht vor (z. B. ist das obige Beispiel nicht praxisgerecht, da beide Abhängigkeiten in der Praxis nicht gelten). 7.4 Normalformen und ER-Modellierung Entityschemata mit einem künstlichen Schlüsselattribut (wie z. B. Personalnr) sind automatisch in 2NF, wenn es keine weiteren Schlüsselkandidaten gibt: Jedes Attribut ist voll funktional abhängig vom Primärschlüssel. In der Praxis gibt es meist auch keine weiteren Schlüsselkandidaten. So wird eine Person unter Umständen noch nicht einmal durch Name Vorname Geburtsdatum Adresse eindeutig identifiziert (z. B. zwei Meier, Sepps, geb. 1.1.1960, wohnhaft in demselben Hochhaus). Sollte es einen weiteren Schlüsselkandidaten geben, so sollte man diesen – im Sinne von BCNF – zusammen mit dem (künstlichen) Primärschlüssel in einer eigenen Tabelle speichern. Abhängigkeiten zwischen Nichtschlüsselattributen sollten – gemäß 3NF – vermieden werden. Nicht Draft (2. März 2000) 118 Ware Wnr DMPreis EuroPreis sondern Ware 0..* Preis 1 Umrechnung Wnr Euro DM oder gar Ware Wnr EuroPreis DMPreis() Das heißt, DMPreis als Methode (= Funktion). In diesem Fall ist nämlich sogar eine mathematische Funktion zur Berechnung der funktionalen Abhängigkeit bekannt. 1 DM = 1 Euro : 1,95 gerundet auf zwei Stellen Diese „Methode“ wird aber vermutlich nicht in SQL ausgeführt (keine Rundungsoperatoren), sondern in einer Hostsprache (Java, C++ etc.). Beziehungen haben mindestens zwei Schlüsselattribute. Funktionale Abhängigkeiten, die sich nicht auf alle Foreign Keys beziehen, sind i. Allg. auf Designfehler zurückzuführen. Student 0..* 0..* Fach Name Matnr Klausur Prüfer Studentenname Prüfung Student Fach Prüfer Studentenname 119 Draft (2. März 2000) Student ï Studentenname ô nicht 2NF Designfehler: Der Studentenname gehört zum Studenten Mehrwertige Abhängigkeiten entstehen i. Allg. durch mengenwertige Attribute Name Hobbies Geburtstagsjahr Wolfgang {Tischtennis, 1961 Akkordeon, Fahrrad} ô 1NF-Form Wolfgang Tischtennis 1961 Wolfgang Akkordeon 1961 Wolfgang Fahrrad 1961 Die redundante, nicht gewollte Speicherung von Wolfgang und 1961 ist auf eine schlechte 1NF-Repräsentation zurückzuführen. Wie bereits bekannt, realisieren wir Person Name: String Hobbies: list<String> Geburtsjahr: Date durch Person Hobby 0..* 0..* Hobby: String Name: String Geburtsjahr: Date d. h. durch mehrere Tabellen. Deshalb treten mehrwertige Abhängigkeiten (i. Allg.) nicht auf und müssen nicht weiter berücksichtigt werden ( ô keine 4NFProbleme). 5VF-Probleme sind bei umfangreichen DB-Schemata nur schwer zu erkennen und werden daher i. Allg. nicht berücksichtigt. Draft (2. März 2000) 120 Anhang A Literatur A.1 Datenbanken C HEN [1976] The Entity-Relationship Model: Towards a unified view of Data, In: ACM Transactions on Database Systems, 1(1), Seiten 9–36 A.2 Objektorientierung KOWARSCHICK , W. [1994] Praxis wissensbasierter Systeme, Vorlesungsskript, Universität Augsburg RUMBAUGH , J., B LAHA , M., P REMERLANI , W., E DDY, F., L ORENSEN , W. [1991] Object-Oriented Modeling and Design, Prentice-Hall RUMBAUGH , J., B LAHA , M., P REMERLANI , W., E DDY, F., L ORENSEN , W. [1993] Objektorientiertes Modellieren und Entwerfen, Hanser Verlag, Prentice-Hall F LANAGAN , D. [1996] Java in a Nutshell, O’Reilly International Thomson F LANAGAN , D. [1998] Java in a Nutshell – Deutsche Ausgabe, O’Reilly International Thomson H ORSTMANN , C., C ORNELL , G. [1997] Core Java, Band I – Fundamentals, SUN Microsystems Press, Prentice Hall H ORSTMANN , C., C ORNELL , G. [1998] Core Java, Band II – Advanced Features, SUN Microsystems Press, Prentice Hall KÖSTLER , G., KOWARSCHICK , W., K IESSLING , W. [1997] Client-Server Optimization for Multimedia Document Exchange, In: Procee- 121 Draft (2. März 2000) dings of the Fifth International Conference on Database Systems for Advanced Applications (DASFAA’97), Seiten 135–144, Melbourne, Australia Draft (2. März 2000) 122