Leopold-Franzens-Universität Innsbruck Institut für Informatik Datenbanken und Informationssysteme Übungstool für relationale Algebra Bachelor-Arbeit Johannes Kessler betreut von Michael Tschuggnall, MSc Univ. Prof. Dr. Günther Specht Innsbruck, 16. Mai 2014 Zusammenfassung Die relationale Algebra ist eine prozedurale Abfragesprache und theoretisches Fundament eines relationalen Datenbanksystems. Sie bildet die Grundlage zum tieferen Verständnis der Arbeitsweise einer Datenbank und wird in Datenbank-Vorlesungen ausführlich behandelt. Im Gegensatz zu anderen Abfragesprachen wie SQL gibt es jedoch kaum Programme, die Abfragen in relationaler Algebra unterstützen. Meist wird sie eher theoretisch vermittelt und Beispiele müssen oft händisch berechnet werden. In dieser Arbeit wird ein Übungstool vorgestellt, das Studenten erlaubt, Abfragen in relationaler Algebra und SQL einzugeben und in relationaler Algebra auszuführen. Dadurch soll das Erlernen dieser fundamentalen Konzepte erleichtert und ein Einblick in die grundlegende Funktionsweise einer Datenbank gegeben werden. Das webbasierte Übungstool unterstützt alle Basisoperatoren der relationalen Algebra und viele der erweiterten Operatoren. Abstract The relational algebra is a procedural query language and is the theoretial basis of a relational database system. It is taught in lectures at universities to build the foundation of understanding how database systems work. In the contrast to other query languages like SQL, there are very few programs that allow to run an arbitrary relational algebra statement. It is therefore often told very theoretically and examples have to be calculated manually. In this thesis a platform was developed, that allows students to formulate statements in either SQL or relational algebra. These statements are then translated into and are run as relational algebra. This should allow the users to learn the fundamental concepts more easily and should give them an insight of how a database works. The webbased tool supports all of the basic operators of the relational algrebra and many of the additional operators and concepts. Inhaltsverzeichnis 1 Einleitung V 2 Relationale Algebra 2.1 Relationales Modell und relationale Algebra 2.1.1 Aufbau . . . . . . . . . . . . . . . . 2.1.2 Union-Kompatibilität . . . . . . . . 2.2 Operatoren der relationalen Algebra . . . . 2.2.1 Selektion . . . . . . . . . . . . . . . 2.2.2 Projektion . . . . . . . . . . . . . . . 2.2.3 Umbenennung . . . . . . . . . . . . 2.2.4 Vereinigung . . . . . . . . . . . . . . 2.2.5 Schnittmenge . . . . . . . . . . . . . 2.2.6 Differenz . . . . . . . . . . . . . . . 2.2.7 Kreuzprodukt . . . . . . . . . . . . . 2.2.8 Theta-Join . . . . . . . . . . . . . . 2.2.9 Equi-Join . . . . . . . . . . . . . . . 2.2.10 Natural-Join . . . . . . . . . . . . . 2.2.11 Outer Joins . . . . . . . . . . . . . . 2.2.12 Semi-Joins . . . . . . . . . . . . . . 2.2.13 Anti-Join . . . . . . . . . . . . . . . 2.2.14 Division . . . . . . . . . . . . . . . . 2.2.15 Sortieren . . . . . . . . . . . . . . . 2.2.16 Erweiterung der Projektion . . . . . 2.2.17 Gruppierung und Aggregation . . . . 2.3 Sichtbarkeit . . . . . . . . . . . . . . . . . . 2.4 Operatorbaumdarstellung . . . . . . . . . . 2.5 Präzedenz . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 3 5 6 6 7 8 8 10 11 11 12 12 13 14 15 18 19 19 20 21 22 24 24 25 3 Übungstool 3.1 Relationale Algebra 3.1.1 Syntax . . . . 3.1.2 Kommentare 3.1.3 Zuweisungen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27 29 29 34 34 . . . . . . . . . . . . . . . . III . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . INHALTSVERZEICHNIS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36 38 39 41 43 49 52 4 Grafische Benutzeroberfläche 4.1 Editor . . . . . . . . . . . . . 4.1.1 Syntax-Highlighting . 4.1.2 Fehlermeldungen . . . 4.1.3 Autovervollständigung 4.2 Operatorbaum . . . . . . . . 4.3 Font . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55 56 57 58 58 59 61 3.2 3.3 3.4 3.1.4 Inline-Relationen . 3.1.5 Präzedenz . . . . . 3.1.6 Plaintext Notation 3.1.7 SQL . . . . . . . . Berechnung . . . . . . . . Server . . . . . . . . . . . Geteilte Tabellen . . . . . . . . . . . . 5 Zusammenfassung 65 Literaturverzeichnis 68 IV Johannes Kessler Kapitel 1 Einleitung Das relationale Modell und die relationale Algebra (RA) wurden 1970 von E. F. Codd eingeführt [Cod70]. Sie bilden das theoretische Fundament jedes relationalen Datenbanksystems. Die relationale Algebra ist eine prozedurale Sprache, um Abfragen mit Relationen zu formulieren. Es werden hierfür Operationen definiert, die Relationen (vereinfacht Tabellen) verarbeiten können. Aufgrund ihrer fundamentalen Bedeutung für das Verständnis eines Datenbanksystems wird die relationale Algebra sowohl in den meisten Büchern behandelt, welche die Grundlagen einer Datenbank vermitteln, als auch in Datenbankvorlesungen an Universitäten vorgestellt. Im Gegensatz zu SQL, das den ISO-Standard für den Zugriff auf relationale Datenbanken darstellt, existiert für die relationale Algebra keine breite Unterstützung durch entsprechende Tools oder Backends. Meist wird sie eher theoretisch vermittelt und Beispiele werden oft händisch berechnet. Ziel dieser Bachelorarbeit ist die Entwicklung eines webbasierten Übungstools für relationale Algebra. Es soll die Berechnung von beliebigen RA-Statements auf vorgegebenen Daten ermöglichen. Einzelschritte der Berechnungen sollen in einem Operatorbaum visualisiert und deren Ergebnisse angezeigt werden können. Weiters soll es möglich sein, Statements in SQL eingeben zu können und diese in RA zu übersetzen. Ähnliche Projekte Interaktive Relationale Algebra (IRA) von Henrik Mühe ist ein webbasiertes Tool, um RA-Ausdrücke auf einem vordefinierten Schema zu formulieren und auszuwerten1 . Die Eingabe der Formel erfolgt durch Auswahl der entsprechenden Operatoren und Operanden. Ein bereits 1 http://www-db.in.tum.de/~muehe/ira/ und https://github.com/henrik-muehe/ira, zuletzt besucht am 29.04.2014 V KAPITEL 1. EINLEITUNG eingegebener Teil kann dabei nicht direkt geändert werden, es steht jedoch eine Funktion zur Verfügung, die den jeweils letzten Schritt rückgängig macht. Die Darstellung der eingegebenen Formeln wurde durch serverseitiges Rendering von Latexcode realisiert. Die Berechnung des Ergebnisses erfolgt clientseitig in JavaScript. Relation Algebra Expression Evaluation ist eine Bachelorarbeit von Lucie Molkov an der Masaryk Universität [Mol09]. Die Arbeit behandelt das Parsen von RA-Ausdrücken und das Übersetzen der Statements in SQL. Hierfür wird eine alternative Klartextsyntax für die RA eingeführt und eine Operatorpräzedenz definiert. Eine Berechnung von RA-Statements ist durch ein in Perl implementiertes Programm möglich, das die eingegebenen Abfragen in SQL übersetzt und für die Berechnung an eine verbundene Datenbank weitergibt. select2obaum ist ein webasiertes Programm der Fachhochschule Köln, das vorgegebene oder frei formulierbare SQL-Statements in relationale Algebra übersetzt2 . Das Ergebnis ist ein RA-Ausdruck, der sowohl als Formel als auch als einfacher Operatorbaum dargestellt wird. Eine Auswertung der Abfrage auf echten Daten ist nicht möglich. Relational Algebra Translator (RAT) ist ein Programm, das eingegebene RA-Statements in SQL übersetzt und diese auf einem verbundenen relationalen Datenbanksystem ausführt3 . Neben dem übersetzten SQL-Statement wird das RA-Statement als Operatorbaum dargestellt. Die semantische Prüfung der eigegebenen Abfrage erfolgt indirekt durch das Ausführen des SQL-Statements. RAT wurde mit dem .NetFramework umgesetzt und benötigt eine Installation auf dem Zielrechner. Relational Algebra Evaluator ist ein interaktiver Interpreter“ von ” Nick Everitt4 . Er ist in Java implementiert und bietet dem User ein Textinterface zur Eingabe der RA-Statements. Relationen können dabei aus CSV-Dateien geladen werden. 2 http://edb.gm.fh-koeln.de/select_new/start.jsp?action=, zuletzt besucht am 29.04.2014 3 http://www.slinfo.una.ac.cr/rat/rat.html, zuletzt besucht am 29.04.2014 4 https://code.google.com/p/relational-algebra/, zuletzt besucht am 29.04.2014 VI Johannes Kessler KAPITEL 1. EINLEITUNG Aufbau Kapitel 2 ist eine Einführung in relationale Algebra. Dabei werden alle im Programm unterstützten Operatoren vorgestellt und erklärt, sowie der grundlegende Aufbau von RA-Abfragen und die Gültigkeitsbereiche von Bezeichnern eingeführt. Weiterhin wird eine Operatorpräzedenz eingeführt, die es erlaubt, durch eine implizite Klammerung von Operatoren auf einen Großteil der expliziten Klammerung zu verzichten. In Kapitel 3 werden das umgesetzte Übungstool und dessen Kernkomponenten vorgestellt. Es wird dafür eine für einen Code-Editor geeignete RA-Syntax und deren Grammatik vorgestellt. Außerdem werden mehrere Erweiterungen wie Zuweisungen oder im Code eingebettete Relationen erklärt, die Übersetzung von SQL Statements nach RA eingeführt und das unterstützte SQL Subset definiert. In Kapitel 4 wird die grafische Benutzeroberfläche des umgesetzten Übungstools präsentiert. Dabei werden wichtige Komponenten wie der Editor und der Operatorbaum und die damit verbundenen Erweiterungen vorgestellt. Johannes Kessler 1 Kapitel 2 Relationale Algebra In diesem Kapitel wird die relationale Algebra und deren Operatoren vorgestellt. Hierbei werden alle im Übungstool unterstützen Operatoren im besonderen Hinblick auf die Verwendung von vollqualifizierten Attributnamen eingeführt. 2.1 Relationales Modell und relationale Algebra Das relationale Modell bildet die Grundlage heutiger relationaler Datenbanksysteme. Es wurde mit der relationalen Algebra (RA) Anfang der 70er Jahre von E. F. Codd eingeführt [Cod70]. Die relationale Algebra ist eine formale Sprache, mit der Abfragen formuliert werden können. Sie ist im Gegensatz zu den deklarativen Abfragesprachen, wie SQL, dem Relationen-Tupelkalkül oder dem Domänenkalkül, prozedural. Das bedeutet, dass sie aus einer Abfolge von Operationen besteht, die beschreiben, wie das Ergebnis berechnet wird. Die deklartiven Abfragesprachen beschreiben, welche Eigenschaften das Ergebnis haben soll, nicht aber, wie dieses berechnet werden soll. Das relationale Modell folgt einem einfachen Aufbau und besteht (grundsätzlich) aus Tabellen (Relationen), in denen die Daten zeilenweise gespeichert sind. Die Zeilen der Relationen (Tupel) haben keine feste Ordnung innerhalb der Relation. Duplikate (Zeilen mit gleichem Inhalt) sind innerhalb einer Relation nicht möglich. Alle Einträge einer Spalte haben denselben Datentyp (Domäne). Formal [KE11, GMUW09] ist eine Domäne ein bestimmter Wertebereich oder Typ, der nur atomare Werte wie beispielsweise die Menge der natürlichen Zahlen oder Zeichenketten enthält. Nicht zugelassen sind strukturierte Typen wie Mengen oder Multimengen. Eine Relation R wird als Teilmenge aus dem Kreuzprodukt aus n Do- 3 KAPITEL 2. RELATIONALE ALGEBRA mänen definiert [KE11, Seite 71]: R Ď D1 ˆ ¨ ¨ ¨ ˆ Dn |n ě 1 Ein Element der Relation R wird als Tupel bezeichnet und besitzt die Stelligkeit n. Eine Relation ist eine Menge, welche daher keine Duplikate enthält und deren Elemente keine Ordnung besitzen. In dieser Arbeit werden Relationen als Tabellen dargestellt, was am Beispiel einer Kundentabelle Kunden Ď string ˆ string ˆ integer veranschaulicht werden soll: Vorname Kunden := Max Johann Nachname Mustermann Meier Kundennummer 100 101 Eine Spalte wird als Attribut bezeichnet und dieser ein innerhalb der Relation eindeutiger Name zugewiesen. Im gegebenen Beispiel werden die Attribute Vorname, Nachname und Kundennummer verwendet. Die Menge der Attribute einer Relation wird als Schema bezeichnet. Attribut Tupel Relation Abbildung 2.1: Bezeichnungen einer Relation als Tabelle dargestellt. Quelle: http://en.wikipedia.org/wiki/File:Relational_ database_terms.svg, zuletzt besucht am 29.04.2014. Das Schema einer Relation R (sch(R)) wird in dieser Arbeit wie folgt dargestellt: [Attributname1 : Attributtyp1 , . . . , Attributnamen : Attributtypn ] Der Attributname ist ein vollqualifizierter Name in der Form Relationsname.Spaltenname und der Attributtyp der Bezeichner der jeweiligen Domäne. Das Schema der Relation Kunden wird somit als [Kunden.V orname : string, Kunden.N achname : string, Kunden.Kundennummer : integer] 4 Johannes Kessler KAPITEL 2. RELATIONALE ALGEBRA dargestellt. Um die Attribute einer Relation eindeutig ansprechen zu können, kann entweder der Name des Attributs verwendet werden, oder dessen Index (1-basiert) in eckigen Klammern. Beiden Varianten muss, wenn anders nicht eindeutig, ein Qualifizierer vorangestellt werden, der durch einen Punkt getrennt wird. Somit kann die erste Spalte der Kundenrelation sowohl mit Vorname“, Kunden.Vorname“, [1]“ als auch mit Kun” ” ” ” den.[1]“ angesprochen werden. In diesem Kapitel werden drei verschiedene Typen verwendet: integer, float und strings. Strings werden dabei analog zu SQL in einfachen Anführungszeichen notiert. 2.1.1 Aufbau In diesem Abschnitt wird der Aufbau einer Formel in relationaler Algebra erklärt. Eine benannte Relation ist eine Relation, der ein Name zugewiesen wurde und den Ausgangspunkt jedes RA-Ausdrucks bildet. Sie wird innerhalb der Formel durch ihren Namen, z.B. Kunden, angesprochen. Zusätzlich kann jeder Ausdruck, nach einer entsprechenden Zuweisung, über den neuen Variablennamen angesprochen werden: A = (Kunde)⨯ρx (Konto) πvorname,nachname,kontostand (A) Jede unäre Operation folgt der folgenden Syntax: αβ (R) wobei α ein der Funktion entsprechendes Symbol (z.B. π für die Projektion), β das Argument und R eine Relation bezeichnet. Eine binäre Operation wird als (R)αβ (S) notiert. Dabei stehen R und S für die übergebenen Relationen, α für die Funktion (z.B. ⨝ für einen Natural-Join) und β für das Argument der Funktion. Für die Relationen R und S können entweder der Name einer benannten Relation oder ein beliebiger Ausdruck in RA eingesetzt werden. Die Klammerung kann entfallen, solange der Ausdruck weiterhin eindeutig definiert ist. Hierzu wird in Abschnitt 2.5 eine Operatorpräzedenz eingeführt. Johannes Kessler 5 KAPITEL 2. RELATIONALE ALGEBRA Das Statement πnachname σvorname‰1 M ax1 Kunde ist auch ohne Präzedenzregeln eindeutig. Das Argument β ist nicht bei allen Operationen vorhanden, wobei sich die Semantik des Operators dabei ändern kann. Als Beispiel kann hierfür der Natural- und Theta-Join (siehe Abschnitt 2.2.10 und Abschnitt 2.2.8) genannt werden. Beide werden mit demselben Symbol ⨝ bezeichnet. Die Unterscheidung erfolgt dadurch, dass ein Theta-Join R ⨝ R.a=S.b S ein zusätzliches Argument β (hier R.a = S.b) besitzt, der Natural-Join R⨝S hingegen nicht. 2.1.2 Union-Kompatibilität Bestimmte Operationen der relationalen Algebra wie Vereinigung, Schnitt und Differenz verlangen union-Kompatibilität. unionKompatibilität ist eine Eigenschaft des Schemas einer Relation. Zwei Relationen R und S sind genau dann union-kompatibel, wenn folgende Bedingungen erfüllt sind: 1. Die Relationen R und S besitzen dieselbe Stelligkeit n, d.h. sie haben die selbe Anzahl von Spalten. 2. Für alle Spalten der Relationen gilt, dass die Domäne der i-ten Spalte der Relation R mit dem Typ der i-ten Spalte der Relation S übereinstimmt (0 ă i ă n). Die Namen der Attribute spielen dabei keine Rolle. Die Schemata [a : string, b : integer, c : integer] und [d : string, e : integer, f : integer] sind somit union-kompatibel, da sie die selbe Anzahl von Attributen besitzen und die Typen der Spalten jeweils paarweise übereinstimmen. 2.2 Operatoren der relationalen Algebra In diesem Abschnitt werden die Operatoren der relationalen Algebra vorgestellt. Jeder Operation der RA werden eine oder zwei Relationen als Argumente übergeben. Der Rückgabewert ist jeweils eine neue Relation, welche das Ergebnis der Operation enthält. Die Argumentrelationen werden dabei nicht verändert. 6 Johannes Kessler KAPITEL 2. RELATIONALE ALGEBRA Zur einfacheren Darstellung wird in diesem Kapitel teilweise davon gesprochen, dass eine Operation eine bestimmte Relation oder ein Schema verändert, wobei darunter immer die Erzeugung einer neuen Relation oder eines Schemas zu verstehen ist, welche die entsprechenden Änderungen enthält. 2.2.1 Selektion Die Selektion dient dazu, bestimmte Tupel (Zeilen) auszuwählen und wird mit σ bezeichnet. Die Selektion X = σC (R) besteht aus einer Relation R und einer Selektionsbedingung C. Die Ergebnisrelation X hat dasselbe Schema und besteht aus jenen Tupeln, welche die Selektionsbedingung C erfüllen (siehe Beispiel 2.1). σaď2_b=’c’ R.a 1 2 3 6 R.b a b b c R.a = 1 2 6 R.b a b c Beispiel 2.1: Selektion. Die Selektionsbedingung C ist ein bedingter Ausdruck, wie er auch in Programmiersprachen wie Java oder C verwendet wird und der folgenden Struktur entspricht: 1. Es werden die logischen Operatoren ^, _ und ␣ verwendet. 2. Die Operanden sind (a) boolsche Konstanten (true oder false) oder (b) Vergleiche von zwei Werten gleichen Typs mit den Operatoren =, ě, ď und ‰. Die Werte stammen von Attributen der Relation oder sind konstante Werte der jeweiligen Domäne. Die Bedingung bezieht sich jeweils auf ein einzelnes Tupel und wird auch für andere Operationen wie den Theta-Join verwendet. Johannes Kessler 7 KAPITEL 2. RELATIONALE ALGEBRA 2.2.2 Projektion Die Projektion ist eine unäre Operation und wird als X = πa 1 , a2 , . . . , an (R) loooooomoooooon Attribute notiert, wobei a1 bis an Attribute der Relation R sind. Im Gegensatz zur Selektion werden bei der Projektion keine Zeilen, sondern bestimmte Spalten in die neue Relation X übernommen. Die Tupel der Ergebnisrelation enthalten nur jene Attribute, die als Argument angegeben wurden (siehe Beispiel Beispiel 2.2). R.a 1 πc,b 2 3 R.b a b b R.c R.c 1 = 1 1 1 1 R.b a b Beispiel 2.2: Projektion. 2.2.3 Umbenennung Attribute Um einzelnen Attributen einer Relation einen neuen Namen zuzuweisen, wird die Operation ρ verwendet, die als X = ρb1 Ða1 ,...,bn Ðan (R) notiert wird. R ist hierbei eine Relation, a1 bis an ist eine Teilmenge der Attribute aus R und b1 bis bn sind die neuen Namen in der Ergebnisrelation X. Die Namen der Attribute, die nicht umbenannt werden, übernehmen den Namen aus der Relation R. Die Tupel der Relation R werden ohne Veränderung übernommen, verändert wird nur das Schema (siehe Beispiel 2.3). R.a 1 ρxÐb,yÐc 2 3 R.b a b b R.a R.c 1 1 = 1 2 1 3 R.x a b b R.y 1 1 1 Beispiel 2.3: Umbenennung von Attributen einer Relation. Zu beachten ist hierbei, dass die vollqualifizierten Namen der Attribute innerhalb des neuen Schemas der Relation X eindeutig sein müssen. 8 Johannes Kessler KAPITEL 2. RELATIONALE ALGEBRA Es ist somit möglich, Spalten umzubenennen, wenn diese unterschiedliche Qualifizierer haben, wie in Beispiel 2.4 (a) zu sehen ist. Das Umbenennen ist jedoch nicht möglich, wenn die Attribute durch die Umbenennung nicht mehr eindeutig wären, wie in Beispiel 2.4 (b) zu sehen ist. R.a S.b R.x S.x ρxÐa,xÐb 1 (a) a = 1 a 2 b 2 b R.a R.b ρxÐa,xÐb 1 a = Attribute nicht mehr eindeutig 2 b (b) Beispiel 2.4: Umbenennung von Attributen mit gleichem und unterschiedlichem Qualifizierer innerhalb des Schemas. Relationen Der Qualifizierer von vollqualifizierten Attributnamen wird mit X = ρY (R) verändert. Dabei ist Y der neue Qualifizierer aller Attribute einer Relation R (siehe Beispiel 2.6). Um die Umbenennung durchführen zu können, müssen die unqualifizierten Namen des neuen Schemas eindeutig sein. Die Umbenennung einer Relation mit dem Schema [R.a, S.a], die aus einem Join der Relationen R und S entstehen kann, ist daher erst möglich wenn einer der Spalten ein neuer Name zugewiesen wird, wie in Beispiel 2.5 illustriert wird. R.a ρY ρxÐR.a 1 2 R.x S.a = ρY a 1 b 2 S.a Y.x = 1 a b 2 Y.a a b Beispiel 2.5: Umbenennung von Relationen bei gleichnamigen Spalten. Johannes Kessler 9 KAPITEL 2. RELATIONALE ALGEBRA ρN EW R.a 1 2 3 R.b a b b R.c NEW.a 1 1 = 1 2 1 3 NEW.b a b b NEW.c 1 1 1 Beispiel 2.6: Umbenennung von Relationen. R.a ρY 1 2 R.b R.a 3 ⨝ Y.a=R.a 1 4 2 Y.a Y.b R.a R.b 1 3 1 3 2 4 2 4 R.b 3 = 4 Beispiel 2.7: Join von Relationen mit gleichnamigen Spalten. Durch die Umbenennung kann sichergestellt werden, dass Attribute zweier Relationen, die den selben vollqualifizierten Namen haben, eindeutig angesprochen werden können. Siehe dazu Beispiel 2.7. 2.2.4 Vereinigung Die Vereinigung (union) ist eine Mengenoperation und wird als X =RYS notiert. Das Ergebnis ist eine neue Relation X mit allen Tupeln aus den Relationen R und S. Die Schemata der Relationen müssen dazu union-kompatibel zueinander sein (siehe Abschnitt 2.1.1). Das Schema wird wie in SQL von der (linken) Relation R übernommen, die Namen der Spalten von R und S müssen dabei nicht übereinstimmen. Wie in Beispiel 2.8 zu sehen ist, werden Duplikate (im Beispiel Zeile [1, b]) dabei nicht mehrfach übernommen. R.a 1 2 3 R.b S.d a Y 1 b 3 b R.a S.e 1 b = 2 3 b 1 R.b a b b b Beispiel 2.8: Vereinigung. 10 Johannes Kessler KAPITEL 2. RELATIONALE ALGEBRA 2.2.5 Schnittmenge Die Schnittmenge (intersection) wird als X =RXS notiert, wobei R und S Relationen mit union-kompatiblen Schemata sind (siehe Abschnitt 2.1.1). Die Ergebnisrelation X beinhaltet alle Tupel, die sowohl in R als auch in S enthalten sind. Das Schema wird wie bei der Vereinigung von der linken Relation (R) übernommen. R.a 1 2 3 R.b S.d a X 1 b 3 b S.e R.a b = 3 b R.b b Beispiel 2.9: Schnittmenge. 2.2.6 Differenz Für die Differenz gelten die selben Voraussetzungen und Regeln, wie für die Schnittmenge und die Vereinigung. Die Differenz wird als X =R´S oder X = RzS notiert. Es werden all jene Tupel aus R in die Ergebnisrelation X übernommen, die nicht in S vorkommen. Siehe dazu Beispiel 2.10. R.a 1 2 3 R.b S.d a ´ 1 b 2 b S.e R.a a = 3 b R.b b Beispiel 2.10: Differenz. Johannes Kessler 11 KAPITEL 2. RELATIONALE ALGEBRA 2.2.7 Kreuzprodukt Beim Kreuzprodukt (cross join) X = R⨯S werden alle möglichen Kombinationen der Tupel aus R und S gebildet, die der Form (r, s)|r P R und s P S entsprechen. Siehe dazu Beispiel 2.11. Das Schema ergibt sich aus der Konkatenation der Schemata von R und S. Das Kreuzprodukt mit einer Relation ohne Tupel ergibt eine leere Relation. R.a 1 2 3 R.b S.d a ⨯ 1 b 2 b R.a 1 S.e 1 a = 2 b 2 3 3 R.b a a b b b b S.d 1 2 1 2 1 2 S.e a b a b a b Beispiel 2.11: Kreuzprodukt. 2.2.8 Theta-Join Der Theta-Join X = R ⨝ ΘS ist ein Kreuzprodukt mit einer zusätzlichen Joinbedingung. Von allen Tupeln des Kreuzprodukts werden nur jene übernommen, die die Bedingung Θ erfüllen. Siehe dazu Beispiel 2.12. R.a 1 2 3 R.b S.a a ⨝ R.aěS.a 1 b 2 b R.a 1 S.b 2 a = 2 b 3 3 R.b a b b b b S.a 1 1 2 1 2 S.b a a b a b Beispiel 2.12: Theta-Join. Jeder Theta-Join kann auch durch Kreuzprodukt und Selektion dargestellt werden: R ⨝ Θ S = σΘ (R⨯S) 12 Johannes Kessler KAPITEL 2. RELATIONALE ALGEBRA Siehe dazu Beispiel 2.13. R= R.a 1 2 S.a 1 S= 1 42 X = R ⨝ R.a=S.a S = σR.a=S.a (R⨯S) R.a S.a S.b 1 1 a 1 R.a 1 b = σR.a=S.a 1 42 c = 1 2 1 a 1 2 1 b 2 42 c S.b a b c S.a 1 1 S.b a b Beispiel 2.13: Theta-Join als Kreuzprodukt und Selektion. 2.2.9 Equi-Join Der Equi-Join entspricht einem Theta-Join, wobei die Joinbedingung Θ auf einfache Vergleiche der Form a = b beschränkt ist. Diese Unterscheidung ist wichtig, da es für diese Untergruppe schnellere JoinAlgorithmen wie z.B. den Hashjoin gibt1 . R.a 1 2 3 R.b a ⨝ a=c b b S.d 1 2 4 S.e R.a x = 1 y 2 z R.b a b S.d 1 2 S.e x y Beispiel 2.14: Equi-Join. 1 http://en.wikipedia.org/w/index.php?title=Hash_join&oldid=591594122, zuletzt besucht am 29.04.2014 Johannes Kessler 13 KAPITEL 2. RELATIONALE ALGEBRA 2.2.10 Natural-Join Der Natural-Join X = (R) ⨝ (S) besteht aus den folgenden zwei Schritten: 1. Einem Equi-Join mit allen Paaren von Spalten aus R und S, die denselben Namen haben und 2. einer Projektion, bei der alle Spalten mit gleichem Namen ausgeblendet werden. Die Gleichheit der Namen bezieht sich hierbei auf den unqualifizierten Attributnamen. Da diese zwei Schritte nicht sequenziell ausgeführt werden müssen, sondern eine neue atomare Operation bilden, kann das Schema der Ergebnisrelation X in einem Schritt erzeugt werden. Dies ermöglicht auch Relationen zu joinen, deren vollqualifizierte Attributnamen nicht disjunkt sind, da nur einer davon in das Schema der neuen Relation X übernommen wird. Dadurch ist der Natural-Join idempotent: R ⨝ R = R R.a R.b S.a S.c R.a R.b S.c 1 a = 1 ⨝ 1 a a a 2 b 2 b 2 b b 3 b Beispiel 2.15: Natural-Join. Im Beispiel 2.15 kommt der Spaltenname a sowohl in R als auch in S vor. Laut Definition [KE11, Seite 91] wird bei der impliziten Projektion nur eine der Spalten übernommen. Die Frage, welche der beiden Spalten übernommen wird, ist erst bei Betrachtung des vollqualifizierten Namens von Bedeutung, da die Spalte später entweder als R.a oder S.a ansprechbar ist. In dieser Arbeit wurde daher definiert, dass immer die Spalte der linken Relation (im Beispiel R.a) übernommen wird. Wenn keine gemeinsamen Attribute existieren, gibt es zwei verschiedene Möglichkeiten2 : 1. Es wird verlangt, dass zumindest ein gemeinsames Attribut vorhanden ist. Der Natural-Join kann somit nicht auf zwei Relationen mit disjunkten Attributen angewendet werden. 2 https://en.wikipedia.org/w/index.php?title=Relational_algebra&oldid= 603628483, zuletzt besucht am 29.04.2014 14 Johannes Kessler KAPITEL 2. RELATIONALE ALGEBRA 2. Ohne gemeinsame Attribute verhält sich der Natural-Join genau wie ein Kreuzprodukt. In dieser Arbeit wurde die zweite Interpretation gewählt, da dies dem Verhalten in modernen Datenbanksystemen wie z.B. PostgreSQL entspricht (siehe [Pos, Kapitel 7.2.1.1]). 2.2.11 Outer Joins Bei Outer Joins können ein oder mehrere Werte eines Tupels fehlen. Dieser Zustand wird durch null ausgedrückt. Man spricht hierbei auch von einem null-Wert, wobei null kein Wert einer bestimmten Domäne ist, sondern eine explizite Darstellung, dass das Tupel an dieser Position keinen Wert enthält und ist damit mit der leeren Menge vergleichbar. Left Outer Theta-Join Der Left Outer Join X = (R) ⟕Θ (S) ist einem Theta-Join sehr ähnlich. Die Werte eines Tupels der linken Relation R bleiben jedoch auf jeden Fall erhalten, auch wenn kein entsprechender Joinpartner in der Relation S gefunden wird, die Joinbedingung Θ also für r in Kombination mit allen Tupeln aus S false ergibt. Für jedes Tupel der Relation R wird mit allen Tupeln aus S ein Join-Paar gebildet, wenn die Joinbedingung Θ erfüllt ist. Wenn kein Joinpartner in S gefunden wurde, wird das Tupel der neuen Relation auf der rechten Seite mit null-Werten aufgefüllt (siehe Beispiel 2.16). R.a 1 2 3 R.b S.a a ⟕R.a=S.a 1 b 2 b R.a S.b 1 a = 2 b 3 R.b a b b S.a 1 2 null S.b a b null Beispiel 2.16: Left Outer Theta-Join. Um Bedingungen für Relationen zu formulieren, bei denen null-Werte vorkommen können, muss eine dreiwertige Logik, analog zu SQL, verwendet werden. Dabei werden die logischen Zustände true und false um einen dritten Zustand unknown erweitert. Ein Vergleich von null mit einem nicht null-Wert ergibt immer unknown. Bei zwei null-Werten ergeben =, ě und ď true, ą, ă und ‰ false. Auch die Operatoren ^, _ und ␣ müssen, wie in Tabelle 2.1 gezeigt, erweitert werden, wobei die Präzedenz erhalten bleibt. Johannes Kessler 15 KAPITEL 2. RELATIONALE ALGEBRA ^ true false unknown true true false unknown _ true false unknown true true true true ␣ true false false false false false unknown unknown unknown unknown false true false unknown unknown true unknown unknown false true unknown unknown Tabelle 2.1: Wahrheitstabellen der Operatoren der dreiwertigen Logik. Quelle: [GMUW09, Seite 254]. Left Outer Natural-Join Der Left Outer Natural-Join X = (R)⟕(S) vereint analog zum Natural-Join • eine Projektion, bei der alle Spalten gleichen Namens ausgeblendet werden und • einen Left Outer Theta-Join, bei dem die Joinbedingung Θ durch die Paare von Spalten mit gleichem Namen definiert ist. Bei der Projektion geht jeweils die Spalte gleichen Namens aus der rechten Relation S verloren. Siehe dazu Beispiel 2.17. R.a 1 2 3 R.b S.b a ⟕ a a b d R.a S.c 1 5 = 2 6 3 R.b a a d S.c 5 5 null Beispiel 2.17: Left Outer Natural-Join. Right Outer Joins Der Right Outer Natural-Join X = (R) ⟕ (S) 16 Johannes Kessler KAPITEL 2. RELATIONALE ALGEBRA und der Right Outer Theta-Join X = (R) ⟕Θ (S) verhalten sich analog zum jeweiligen Left Outer Join, nur dass hierbei die Werte der rechten Relation S bestehen bleiben und links mit nullWerten aufgefüllt wird, wenn kein Joinpartner in der linken Relation R vorhanden ist. Beim Right Outer Natural-Join geht jeweils die Spalte gleichen Namens aus der linken Relation R verloren. Siehe dazu Beispiel 2.18 und Beispiel 2.19. S.a S.c R.b R.a S.a S.c R.b R.a 1 a a 1 1 a a = 1 ⟖R.a=S.a 2 b b 2 2 b b 2 3 b null null 3 b Beispiel 2.18: Right Outer Theta-Join. S.a R.a 1 1 ⟖ 2 2 3 R.b a b S.c R.b a = a b b b null S.a 1 2 3 S.c a b b Beispiel 2.19: Right Outer Natural-Join. Full Outer Joins Der Full Outer Join X = (R)⟗(S) und der Full Outer Theta-Join X = (R)⟗Θ (S) vereinen die Eigenschaften des Left- und Right Outer Joins. Wenn kein Joinpartner für ein Tupel der linken Relation R gefunden wird, wird rechts mit null-Werten aufgefüllt, und wenn keiner für ein Tupel der rechten Relation S gefunden wird, wird links aufgefüllt. Das Schema wird jeweils durch die Konkatenation der Schemata von R und S gebildet. Siehe dazu Beispiel 2.20. Der Full Outer Theta-Join kann auch durch eine Vereinigung von Leftund Right Outer Theta-Join dargestellt werden: R ⟗Θ S = (R ⟕Θ S) Y (R ⟖Θ S) Johannes Kessler 17 KAPITEL 2. RELATIONALE ALGEBRA R.a 1 2 R.b S.b a ⟗ b b d R.a S.c 1 42 = 2 42 null R.b a b null S.b null b d S.c null 42 42 Beispiel 2.20: Full Outer Natural-Join. 2.2.12 Semi-Joins Der Left Semi-Join X = (R) ⋉ (S) eliminiert alle Tupel der Relation R, für die kein Joinpartner in S gefunden wird. Beim Right Semi-Join X = (R) ⋊ (S) werden alle Tupel aus S nicht übernommen, die in R keine Joinpartner haben. Joinbedingung ist analog zum Natural-Join, dass Spalten der Relationen R und S, die den gleichen Namen haben, idente Werte aufweisen müssen (siehe Abschnitt 2.2.10). Das Schema entspricht nach der Ausführung des Left Semi-Joins dem der linken Relation R, nach der Ausführung des Right Semi-Joins dem der rechten Relation S. sch(R ⋉ S) = sch(R) sch(R ⋊ S) = sch(S) Der Semi-Join kann daher auch als Theta-Join (R ⨝ Θ S) mit nachfolgender Projektion auf die Attribute einer der Relationen angesehen werden, wobei die Joinbedingung Θ analog zum Natural-Join gebildet wird. Hierbei ist jedoch zu beachten, dass beim Theta-Join temporär eine neue Relation entsteht, deren Schema aus der Konkatenation der Schemata von R und S gebildet wird. Beim Semi-Join werden jedoch nur von einer der Relationen Zeilen entfernt bzw. nicht in die neue Relation X übernommen. Da innerhalb eines Schemas die voll qualifizierten Namen eindeutig sein müssen, kann ein Theta-Join nicht ausgeführt werden, wenn dieselben voll qualifizierten Namen in beiden Relationen vorkommen. Beim SemiJoin besteht diese Einschränkung nicht. Dies kann anhand eines Self-Joins (Join einer Relation mit sich selbst) veranschaulicht werden: 18 Johannes Kessler KAPITEL 2. RELATIONALE ALGEBRA Der Self-Join mithilfe eines Semi-Joins R = R⋉R = R⋊R ist problemlos möglich, da die Schemata nicht konkateniert werden müssen. Der Self-Join mit einem Theta-Join R ⨝ true R ist jedoch nicht möglich, da das neue Schema nicht gebildet werden kann. 2.2.13 Anti-Join Der Anti-Join oder Anti Semi-Join X = (R) ◁ (S) selektiert das Komplement des (Left) Semi-Joins. In der Relation X sind damit all jene Tupel aus R enthalten, die keinen Joinpartner in S haben. Der Anti-Join kann auch durch R ◁ S = R ´ (R ⋉ S) ausgedrückt werden. 2.2.14 Division Die relationale Division X =R˜S ist eine binäre Operation und kann folgendermaßen durch andere Operatoren ausgedrückt werden [KE11, Seite 97]: R = sch(R) S = sch(S) R1 = R ´ S R ˜ S = πR1 (R) ´ πR1 ((πR1 (R)⨯S) ´ R) S muss hierbei eine echte Teilmenge von R sein. Das Schema R1 besteht aus jenen Attributen der Relation R, die nicht Attribut der Relation S sind. R1 ist somit die Differenz der Schemata: R1 = sch(X) = sch(R) ´ sch(S) Die Tupel der Ergebnisrelation X bestehen aus einem Subset der Tupel aus R (definiert durch (R1 )), bei denen alle Kombinationen mit allen Tupeln aus S in R enthalten sind. Die Kombinationen entsprechen hierbei der Form [tr , ts ], wobei tr ein Tupel der Relation R und ts ein Tupel der Relation S ist. Johannes Kessler 19 KAPITEL 2. RELATIONALE ALGEBRA R.a 1 1 1 R.b a c e R.c b d f 2 2 a c b d 3 4 5 a c e b d f S.b ˜ a c R.a S.c b = 1 d 2 Beispiel 2.21: relationale Division. 2.2.15 Sortieren Sortieren von Tupeln innerhalb einer Relation ist in der klassischen relationalen Algebra nicht möglich, da Relationen Mengen von Tupeln sind und die Tupel darin - per Definition - keine Ordnung haben. Der hier vorgestellte Sortieroperator [GMUW09, Seite 219] kann daher nur angewendet werden, wenn diese Einschränkung aufgehoben wird, wie in [GMUW09, Kapitel 5.1] erläutert wird. In dieser Arbeit wird ein zusätzlicher Sortieroperator vorgestellt, da dieser mehrere Vorteile bietet: 1. Durch eine sortierte Ausgabe können Ergebnisse verschiedener Abfragen einfacher verglichen werden, 2. er ermöglicht die Darstellung der SQL-order by-Operation als eigene RA-Operation und 3. er ermöglicht die Ausgabe des Programms mit Beispielen aus Vorlesungsunterlagen oder Büchern einfacher zu vergleichen. Der Sortieroperator X = τa 1 asc,a2 desc,...,an (R) sortiert die Tupel der Relation R nach den übergebenen Attributen (a1 bis an ). Nach jedem Attribut kann zusätzlich eine optionale Sortierrichtung angegeben werden: asc für aufsteigend und desc für absteigend. Ohne explizite Angabe der Reihenfolge wird asc angenommen (siehe Spalte b in Beispiel 2.22). Das Schema wird dabei nicht verändert. sch(τa1 ,...,an (R)) = sch(R) 20 Johannes Kessler KAPITEL 2. RELATIONALE ALGEBRA τa desc,b R.a 1 1 2 2 R.b a c b d R.c 42 0 128 4 = R.a 2 2 1 1 R.b b d a c R.c 128 4 42 0 Beispiel 2.22: Sortieren einer Relation. 2.2.16 Erweiterung der Projektion Durch Einführung einer Ordnung der Tupel durch Lockerung des strikten Mengenbegriffs (wie in Abschnitt 2.2.15 beschieben wurde), liegt die Idee nahe, diese Ordnung für Abfragen nutzbar zu machen. In SQL besteht diese Möglichkeit je nach Datenbanksystem durch die Limit und Offset Klausel oder durch eine virtuelle Spalte rownum“, ” welche den Zeilenindex jeder Zeile der Tabelle enthält. Damit sind Abfragen wie “Top 10 Kunden mit den meisten Bestellungen möglich die auf einer horizontalen Partitionierung unter ” Ausnutzung der Ordnung beruhen. In dieser Arbeit wurde die Projektion dafür um einen virtuelle Spalte namens ROWNUM“ erweitert. ” Solange kein Attribut mit dem Namen ROWNUM im Schema enthalten ist, kann damit der Tupelindex (1-basiert) der Argumentrelation ausgegeben werden. Die dadurch entstehende neue Spalte mit Integerwerten kann in allen folgenden Operationen wie jede andere Spalte behandelt werden. In Beispiel 2.23 werden die besten drei Studenten einer Prüfung gesucht. Dazu wird die Relation zuerst nach den Noten sortiert um im nächsten Schritt den Tupelindex ROWNUM hinzuzufügen. Über diese neue Spalte werden bei der Selektion die fünf ersten Einträge ausgewählt. Für die Ausgabe könnte die Spalte ROWNUM über eine weitere Projektion ausgeblendet werden. Johannes Kessler 21 KAPITEL 2. RELATIONALE ALGEBRA MatrNr 42 43 σROW N U M ă=3 (πROW N U M,[1],[2] (τN ote asc 45 46 48 59 ROWNUM R.MatrNr R.Note 1 42 1 2 59 1 3 45 2 Note 1 3 2 4 5 1 )) = Beispiel 2.23: Verwendung des Tupelindex innerhalb einer RA-Abfrage. 2.2.17 Gruppierung und Aggregation Bei der Gruppierung werden die Tupel einer Relation zu Gruppen zusammengefasst. Dabei sind all jene Tupel in einer gemeinsamen Gruppe die bei allen Gruppierungsattributen die selben Werte aufweisen. Auf alle Tupel einer Gruppe können Aggregationsfunktionen wie das Aufsummieren aller Werte angewandt werden. Die hier vorgestellte Aggregation entspricht einer Mischung aus den Definitionen in [KE11, Seite 97] und [GMUW09, Seite 214]. Durch die strikte Trennung von Gruppierung und Aggregation in der Syntax von [KE11] ist klarer ersichtlich, dass es sich dabei um zwei separate Schritte handelt. Die direkte Benennung der durch die Aggregation entstehenden Spalten in [GMUW09] ermöglicht eine einfache Weiterverwendung der Attribute über den zugewiesenen Namen. Die Attribute nach denen gruppiert wird, sind wie in [GMUW09] optional. Die Aggregation wird mit X = γa1 , . . . , an ;AGG1 Ñ x1 , . . . , AGGn Ñ xn (R) loooomoooon looooooooooooooooooomooooooooooooooooooon Gruppierung Aggregation notiert. Wobei a1 bis an die Attribute sind nach denen gruppiert wird, AGG1 bis AGGn sind die Aggregationsfunktionen die auf alle Tupel der Gruppen angewandt werden und x1 bis xn sind die Namen der Aggregationsspalten in der Ergebnisrelation X. Die Angabe der Gruppierungsattribute ist optional. Wenn keine Gruppierung angegeben ist, gibt es eine einzelnen Gruppe welche alle Tupel der Relation R enthält (siehe Beispiel 2.24). Der Strichpunkt kann dabei entfallen. 22 Johannes Kessler KAPITEL 2. RELATIONALE ALGEBRA γSU M (b)Ñz,AV G(b)Ñy,M IN (a)Ñz R.a 1 1 2 2 R.b a c b d = x 6 y 2 z a Beispiel 2.24: Aggregation ohne explizite Angabe einer Gruppierung. Für die Aggregation stehen die in Tabelle 2.2 aufgelisteten Aggregationsfunktionen zur Verfügung. Die Beschreibung bezieht sich dabei immer auf die Werte einer Gruppe. Die Rückgabewerte der Funktionen COU N T (˚) und COU N T (Attribut) sind Integer. Die Funktion AV G(x) gibt einen Float-Wert zurück. Bei allen anderen entspricht der Typ der Rückgabe dem Typ des übergebenen Attributs. Funktion COU N T (˚) COU N T (x) M IN (x) M AX(x) SU M (x) AV G(x) Beschreibung Anzahl der Tupel der Gruppe Anzahl der nicht null-Werte der Spalte x minimaler Wert der Spalte x maximaler Wert der Spalte x Summe aller nicht null-Werte der Spalte x Durchschnitt aller nicht null-Werte der Spalte x Tabelle 2.2: Aggregationsfunktionen in der relationalen Algebra. Johannes Kessler 23 KAPITEL 2. RELATIONALE ALGEBRA R= VorlNr 1 1 1 2 2 2 3 3 MatrNr 42 43 45 42 43 46 42 43 Note 1 2 4 3 2 5 2 1 γV orlN r;COU N T (˚)Ñteilnehmer,AV G(N ote)Ñdurchschnitt (R) = R.VorlNr 1 = 2 3 teilnehmer 3 3 2 durchschnitt 2.33 3.33 1.5 Beispiel 2.25: Aggregation ohne explizite Angabe einer Gruppierung. Wie in Beispiel 2.25 zu sehen ist können durch Verwendung der Gruppierung und Aggregation somit Abfragen wie die durchschnittliche Note ” pro Fach“ sehr einfach formuliert werden. 2.3 Sichtbarkeit Unter dem Sichtbarkeitsbereich (scope) versteht man einen bestimmten Bereich, in dem ein Bezeichner sichtbar und ansprechbar ist. Eine benannte Relation ist global gültig. Ihr Name kann damit in der gesamten Abfrage verwendet werden und muss auch global eindeutig sein. Die Attribute einer Relation sind lokal gültig und müssen innerhalb des Schemas eindeutig sein. Es kann jedoch nötig sein, Attributnamen oder den qualifizierenden Relationsnamen zu ändern, um die Attribute bei binären Operationen eindeutig ansprechen zu können oder die Konkatenation von zwei Schemata zu ermöglichen, die sich Attributnamen teilen (siehe Abschnitt 2.2.3). 2.4 Operatorbaumdarstellung Beim Lesen komplexer Ausdrücke ist oft eine Darstellung der Formel als Operatorbaum hilfreich. Hierbei bilden die einzelnen Operatoren die Knoten eines Baumes, wobei die Argumentrelationen der Operatoren 24 Johannes Kessler KAPITEL 2. RELATIONALE ALGEBRA jeweils als Kindelemente im Baum dargestellt werden. Die Auswertung des Ausdrucks erfolgt bottom-up. Die Abfrage ( ) ( )) ( πR.a,R.b,S.d πa,b σaąb_a=1 (R ⨝ ρS X) ⨝ R.a=S.c σcą10 (S) kann somit als Operatorbaum dargestellt werden, wie in Abbildung 2.2 veranschaulicht ist. . πR.a,R.b,S.d ⨝ R.a=S.c πa,b σcą10 σaąb_a=1 S ⨝ ρS R X Abbildung 2.2: Operatorbaumdarstellung einer RA-Formel. 2.5 Präzedenz Die Operatorpräzedenz legt die Ordnung fest, nach der die Operatoren ausgewertet werden, wenn diese nicht explizit geklammert sind. Ohne Präzedenz ist das Statement σaą0 R ⨝ S nicht eindeutig definiert, da es zwei mögliche Auswertungsreihenfolgen gibt (hier explizit geklammert): 1. σaą0 (R ⨝ S), wobei hier zuerst der Join ausgewertet wird oder 2. (σaą0 (R)) ⨝ S, bei der R zuerst selektiert wird. Johannes Kessler 25 KAPITEL 2. RELATIONALE ALGEBRA In der Literatur gibt es keine eindeutige Übereinkunft über die Wertigkeit der Operatoren [Mol09, Seite 24-25], [Ull04, slides5 Seite 21]. Gemeinsam ist den meisten Definitionen, dass die unären Operatoren die höchste Wertigkeit haben, gefolgt von den Joins und den Mengenoperatoren (X vor Y). Im Zweifel sollte daher immer explizit geklammert werden. Für diese Arbeit wurde die Operatorpräzedenz wie in Tabelle 2.3 ersichtlich definiert. Die Operatoren werden der Tabelle folgend, von oben nach unten und in jeder Zeile von links nach rechts ausgewertet. Die höchste Bindung hat die benannte Relation. Ein Relationsname gehört daher immer zur Operation. Bei den logischen Operatoren hat ^ (AND) die höchste Präzedenz, gefolgt von ‘ (XOR) und _ (OR). Präzedenz 4 3 2 1 Operator Projektion, Selektion, Umbenennung (Attribute), Umbenennung (Relationen), Gruppieren, Sortieren Kreuzprodukt, Theta-Join, Natural-Join, Left Outer Join, Right Outer Join, Full Outer Join, Left Semi-Join, Right Semi-Join, Anti Semi-Join, Division Schnitt Vereinigung, Differenz Tabelle 2.3: Operatorpräzedenz. Durch die Definition der Präzedenz ist das Statement σaą0 R ⨝ S eindeutig bestimmt, da die unäre Operation σ eine höhere Präzedenz als der Join hat und daher zuerst ausgeführt wird. 26 Johannes Kessler Kapitel 3 Übungstool Im Gegensatz zu SQL kann beim Erlernen der relationalen Algebra und der Kalküle nicht auf eine umfangreiche Unterstützung in modernen Datenbanksystemen zurückgegriffen werden. In der Literatur [GMUW09, KE11, AHV95, AHV95] und in vielen Vorlesungen an Universitäten wird für die RA eine Notation verwendet, welche der in Kapitel 2 vorgestellten sehr ähnlich ist. In den der Datenbankvorlesung zugehörigen Übungen werden die Aufgaben daher von Studenten handschriftlich verfasst oder müssen aufwändig als Formel gesetzt werden. Mangels Toolunterstützung werden die Berechnungen oft händisch ausgeführt. Für Übungsaufgaben in SQL können die nötigen Tabellen auf einer Datenbank zur Verfügung gestellt werden. Die Studenten können über eine webbasierte Abfrageoberfläche wie phpMyAdmin1 darauf zugreifen und ihre formulierten Abfragen direkt testen. Die Grundidee des Übungstools für relationale Algebra ist es, ein vergleichbares Angebot für RA zu schaffen, das die Möglichkeit bietet, Abfragen in der erlernten Notation zu verfassen und auf vorgegebenen Datensätzen auszuführen. Dies ermöglicht den Benutzern, Beispiele in der Literatur einfach nachzurechnen und zu erweitern. Die flexible Eingabe als Klartext-Statement (siehe Abschnitt 3.1.6 auf Seite 39) ermöglicht eine iterative Erarbeitung von Statements. Weiters soll den Benutzern eine experimentierfreundliche Umgebung geboten werden, die es ermöglicht, alternative Lösungswege zu erarbeiten. Das webbasierte Programm sollte daher mindestens folgende Anforderungen erfüllen: • einfache Bedienung für die Benutzer • ohne Installation zusätzlicher Software lauffähig 1 http://phpmyadmin.net/, zuletzt besucht am 29.04.2014 27 KAPITEL 3. ÜBUNGSTOOL • die verwendete Syntax soll möglichst nahe an der klassischen“ ” Notation sein • Visualisierung der Abfrage als Operatorbaum • Anzeige von Zwischenergebnissen Die Anwendung besteht aus den folgenden Komponenten: Eine Grammatik für die relationale Algebra und SQL, aus diesen jeweils ein Parser generiert wird. Diese Parser erzeugen den Syntaxbaum eines eingegebenen Statements (siehe Abschnitt 3.1). Die Business-Logik’‘ ist eine Implementierung der relationalen Algebra ” und umfasst über 2000 Zeilen JavaScript Code (siehe Abschnitt 3.2). Eine Übersetzungsschicht übersetzt die Syntaxbäume in die relationale Algebra. Das Übungstool ist auf aktuellen Browsern lauffähig und wurde in den in Tabelle 3.1 aufgelisteten Versionen getestet. Microsofts Internet Explorer wird ab Version 10 unterstützt. Für alle älteren Versionen wird eine entsprechende Meldung eingeblendet. Browser Google Chrome 35 (beta) Mozilla Firefox 29 Opera 12 rekonq 2.4.2 Google Chrome 34 Mozilla Firefox 29 Apple Safari 7 Opera 20 Google Chrome 34 Mozilla Firefox 29 Opera 20 Microsoft Internet Explorer Microsoft Internet Explorer Microsoft Internet Explorer Microsoft Internet Explorer Microsoft Internet Explorer 11 10 11 10 9 Plattform Ubuntu 14.04 Ubuntu 14.04 Ubuntu 14.04 Ubuntu 14.04 OS X OS X OS X OS X Windows 8.1 Windows 8.1 Windows 8.1 Windows 8.1 Windows 8 Windows 7 Windows 7 Windows 7 lauffähig ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja eingeschränkt2 Tabelle 3.1: Liste der Browser, auf denen das Übungstool getestet wurde. 2 Das Laden von Tabellen von Github Gists (Seite 52) funktioniert nicht. 28 Johannes Kessler KAPITEL 3. ÜBUNGSTOOL 3.1 Relationale Algebra Die relationale Algebra (RA) wird klassischerweise als Formel dargestellt (siehe Kapitel 2). In dieser Arbeit wird RA jedoch als Quelltext, vergleichbar mit SQL, aufgefasst. Dies ermöglicht Features wie • das einfache Bearbeiten in einem Editor, • Syntax-Highlighting und • Autovervollständung, die in vielen SQL-Editoren (z.B. MySQL Workbench3 , pgAdmin4 ) enthalten sind, in einem RA-Übungstool anzuwenden. Für diesen Zweck wurde eine Grammatik definiert, die es ermöglicht, RA-Statements in der klassischen Notation fast unverändert zu verarbeiten. Weiters wurden mehrere Erweiterungen wie Kommentare oder Einführung einer alternativen Notation vorgenommen, die in diesem Kapitel vorgestellt werden. 3.1.1 Syntax Die Syntax für RA Statements folgt der in Kapitel 2 vorgestellten klas” sischen“ Notation. Die einzige Änderung besteht darin, dass die in Subscript notierten Argumente nicht tiefergestellt werden. Die Syntax ist nicht zeilenorientiert und die einzelnen Tokens können durch beliebigen Whitespace getrennt werden. Die Operatoren können durch das entsprechende Sonderzeichen oder durch eine Plaintext-Schreibweise notiert werden, die in Abschnitt 3.1.6 vorgestellt wird. Für die Operatoren werden die in Tabelle 4.1 dargestellten Unicode Symbole verwendet. Die RA-Formel π S.N ame,S.Semester,P.N ame ( (V orlesungen ⨝ (ρS Studenten ⨝ ρH hoeren)) ⨝ gelesenV on=P ersN r (ρP P rof essoren)) kann durch die neue Grammatik wie folgt eingegeben werden: 3 4 http://www.mysql.de/products/workbench/, zuletzt besucht am 29.04.2014 http://www.pgadmin.org/, zuletzt besucht am 29.04.2014 Johannes Kessler 29 KAPITEL 3. ÜBUNGSTOOL 1 π S.Name , S.Semester , P.Name ( 2 ( 3 Vorlesungen 4 ⨝ ( 5 ρ S Studenten 6 ⨝ 7 ρ H hoeren 8 ) 9 ) 10 ⨝ gelesenVon = PersNr 11 ρ P Professoren 12 ) Mit der in Abschnitt 3.1.6 vorgestellten alternativen Operatorschreibweise kann auf die Verwendung von Sonderzeichen verzichtet werden: 1 2 3 4 5 6 7 8 9 10 11 12 pi S.Name , S.Semester , P.Name ( ( Vorlesungen natural join ( rho S Studenten natural join rho H hoeren ) ) join gelesenVon = PersNr rho P Professoren ) PEG.js PEG.js5 ist ein von David Majda entwickelter freier Parsergenerator für JavaScript. Er kann direkt im Browser, über eine JavaScript API oder über die Kommandozeile verwendet werden und steht als node.js-Modul6 zur Verfügung. PEG.js verwendet eine sogenannte parsing expression grammar (PEG) [For04], die syntaktisch einer kontextfreien Grammatik (CFG) sehr ähnlich ist. Der Unterschied ist, dass bei PEGs die Produktionen geordnet sind und streng nach der Reihe angewandt werden. Sobald eine Regel anwendbar ist, wird diese verwendet. Der Syntaxbaum ist dadurch immer eindeutig, da Mehrdeutigkeiten in CFGs durch mehrere passende Produktionen entstehen. 1 2 3 4 5 6 5 6 rule1 = 'first parsing expression ' / 'second ' 'parsing '? test:'expression ' { /* action of the second expression */ return { http://pegjs.majda.cz/, zuletzt besucht am 29.04.2014 http://nodejs.org/, zuletzt besucht am 29.04.2014 30 Johannes Kessler KAPITEL 3. ÜBUNGSTOOL 7 8 9 10 11 12 13 a: 'a value ', b: test --variable from parsing expression }; } integer = [0 -9]+ Die Grammatik besteht (vereinfacht) aus Regeln (rules), die durch eindeutige Namen identifiziert werden [Maj14]. Jeder Regel folgt eine geordnete Liste von parsing expressions, die auf den Eingabetext matchen. Sie bieten ähnlich zu regulären Ausdrücken die Möglichkeit, Literale, Klassen von Zeichen und Wiederholungen abzubilden. Jeder parsing expression kann eine action folgen, die von geschwungenen Klammern umfasst wird. Die action besteht aus JavaScript Code, der ausgeführt wird, wenn die expression matcht. Die Werte von Teilen der parsing expression, die als Variablen definiert wurden (im Beispiel test), stehen im JavaScript-Code zur Verfügung. Durch die geordneten expressions kann die Regel test2 in der Grammatik Beispiel 3.1 auf die Eingabe 123abc“ angewandt werden, nicht jedoch ” test1, da der Ausdruck in Zeile 2 auf den Teilstring 123“ matcht. ” 1 2 3 4 5 6 7 test1 = [0 -9]+ / [0 -9]+ [a-z]+ test2 = [0 -9]+ [a-z]+ / [0 -9]+ Beispiel 3.1: PEG.js Grammatik. Grammatik Die Grammatik für die in Abschnitt 3.1.1 eingeführte Syntax wurde mit dem Parsergenerator PEG.js umgesetzt. Die Ausgabe des Parsers ist ein Syntaxbaum, der in einem weiteren Schritt in den ausführbaren Code übersetzt wird. Diese Trennung ermöglicht das separate Testen und Entwickeln des Compilers bzw. der Grammatik und der Ausführungslogik. Weiters können Operationen wie die Ersetzung von Variablen direkt auf dem Syntaxbaum ausgeführt werden (siehe Abschnitt 3.1.3). Die umgesetzte Grammatik soll hier am Beispiel der Selektion und des Theta-Joins vereinfacht dargestellt werden. Die Schlüsselwörter sind jeweils als eigene Regeln ausgeführt, um die alternative Schreibweise zu unterstützen. Johannes Kessler 31 KAPITEL 3. ÜBUNGSTOOL 1 2 3 4 5 6 7 1 2 3 4 5 6 7 8 9 10 11 1 2 3 4 5 6 7 8 9 10 11 12 sigma = 'σ' / 'sigma ' inner = '⨝' / ('inner ' __)? 'join ' selection = sigma __ arg: boolean __ child : expression_precedence3 { return { type: 'selection ', arg: arg , child : child , codeInfo : getCodeInfo () } } thetaJoin = child1 : expression_precedence3 __ inner __ arg: boolean __ child2 : expression { return { type: 'thetaJoin ', arg: arg , child : child1 , child2 : child2 , codeInfo : getCodeInfo () }; } Die Selektion beginnt mit dem Keyword sigma, das wie in den Zeilen 1 bis 3 ersichtlich ist, die verschiedenen alternativen Schreibweisen abdeckt. Die Regel __ wurde als beliebiger, aber nicht optionaler Whitespace definiert, expression_precedence3 steht für einen gültigen RA-Ausdruck und ist als die Gruppe aller unären Operatoren definiert. Dadurch wird die Selektion am stärksten an andere unäre Operatoren und an die benannte Relation als Basis gebunden, da diese früher gematcht werden. Die Regel boolean steht für einen beliebigen boolschen Ausdruck. Der Rückgabewert jeder Aktion eines Operators ist ein JavaScriptObjekt, das zumindest die Eigenschaft type besitzt, die zur Identifikation des Typs jedes Knotens im Syntaxbaum dient. Die Eigenschaften child und child2 enthalten die Subbäume der Operanden. Die Selektion als unärer Operator hat daher nur einen Operanden child. Das generische Objekt codeInfo enthält z.B die Position im Statementcode und wird verwendet, um in späteren Schritten Fehlermeldungen mit genauen Positionsangaben versehen zu können und diese im Editor an der richtigen Position anzeigen zu können. 32 Johannes Kessler KAPITEL 3. ÜBUNGSTOOL Der Theta-Join als Beispiel für einen binären RA-Operator ist analog dazu aufgebaut. Der erste Operand bei binären Operatoren ist jeweils vom Typ der nächst höheren Präzedenzgruppe. Jeder Syntaxbaum einer RA-Abfrage beginnt mit einem Knoten vom Typ root, der alle Zuweisungen und die eigentliche Abfrage enthält. Die Abfrage 1 2 3 sigma a>0 R inner join R.b=S.b S ergibt somit den folgenden (vereinfacht dargestellten) Syntaxbaum: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 { "type": "root", " assignments ": [], "child ": { "type": " thetaJoin ", "arg": { "type": " ConditionConst ", "value ": true , " codeInfo ": {"line": 2, " column ": 12, " offset ": 26, "text": "true"} }, "child ": { "type": " selection ", "arg": { "type": " ConditionConst ", "value ": false , " codeInfo ": {/* ... */} }, "child ": { "type": " relation ", "name": "R", " codeInfo ": {"line": 1," column ": 13, " offset ": 12, "text": "R"} }, " codeInfo ": {/* ... */} }, " child2 ": { "type": " relation ", "name": "S", " codeInfo ": {"line": 3, " column ": 1, " offset ": 31, "text": "S"} }, " codeInfo ": {/* ... */} }, " codeInfo ": {/* ... */} } Johannes Kessler 33 KAPITEL 3. ÜBUNGSTOOL 3.1.2 Kommentare Zum einfachen Kommentieren der Abfragen, auch im Hinblick auf die Abgabe der Lösung einer Übung, sind zwei Arten von Kommentaren verfügbar. Analog zu SQL [Pos, Kapitel 4.1.5] können einzeilige Kommentare mit -- “ eingeleitet werden. ” 1 2 3 π Name , Semester σ semester <= 1 -- nur Erstsemestrige Studenten Mehrzeilige Block-Kommentare werden mit /* und */ umschlossen. 1 2 3 π Name /* , Semester */ σ semester <= 1 -- nur Erstsemestrige Studenten Beide Arten von Kommentaren werden als Whitespace behandelt und sind daher gültige Trenner von zwei Tokens. Beim einzeiligen Kommentar muss den zwei Minuszeichen mindestens ein Whitespacezeichen folgen. Dieses beugt einem Problem vor, dass bei einer Einführung von arithmetischen Operationen folgen würde: Der arithmetische Ausdruck a--b wäre nicht gültig, da -- als Kommentar interpretiert würde und nicht als Minusoperator, gefolgt von einem Vorzeichen7 . Dies müsste somit als a-(-1), a - -1 oder a- -1 geschrieben werden. 3.1.3 Zuweisungen Für größere Abfragen in relationaler Algebra ist es nicht unüblich, Teile davon als Variable zu definieren und diese in der eigentlichen Abfrage zu verwenden. Diese Variablen können nach ihrer Definition wie benannte Relationen behandelt werden. Für das Übungstool wurde diese Möglichkeit übernommen. Die Syntax einer solchen Zuweisung ist: VARIABLE = RA_EXPRESSION ist dabei ein beliebiger Ausdruck in relationaler Algebra, ein freier Bezeichner (siehe Beispiel 3.2). Die Variablennamen teilen sich hierbei denselben globalen Namespace wie die benannten Relationen und müssen in diesem eindeutig sein. Die Zuweisung ist hier ein rechtsassoziativer Operator. Die Reihenfolge der Definitionen spielt keine Rolle. Es können auch Variablen innerhalb der Variablendefinition verwendet werden, solange dadurch keine zyklischen Abhängigkeiten entstehen. RA_EXPRESSION VARIABLE 7 https://dev.mysql.com/doc/refman/5.1/de/ansi-diff-comments.html, zuletzt besucht am 29.04.2014 34 Johannes Kessler KAPITEL 3. ÜBUNGSTOOL 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 K = pi kundennr ,vorname , nachname Kunde -- neue Bestellugen B1 = sigma datum > 2014 -01 -01 pi kundennr ,datum , gesamtpreis Bestellungen -- alte Bestellungen B2 = sigma datum < 1970 -01 -01 pi kundennr ,datum , gesamtpreis Bestellungen K natural join (B1 union B2) Beispiel 3.2: Verwendung von Zuweisungen. Die Variablenersetzung erfolgt im Syntaxbaum. Für jede Zuweisung generiert der Parser einen eigenen Unterbaum, der die definierte Abfrage enthält. Im nächsten Schritt werden alle Positionen in den Bäumen der Zuweisungen gesucht, an denen diese Bezeichner verwendet werden. Mithilfe dieser Positionen wird mittels Tiefensuche sichergestellt, dass keine zyklischen Zuweisungen vorhanden sind, da ansonsten die Ersetzung nicht terminieren würde. Jede Verwendung einer Variable wird im letzten Schritt mit deren Definition ersetzt und die Ersetzung für die spätere Visualisierung im Operatorbaum (Abschnitt 4.2) in den Metadaten des Knotens gespeichert. Im Operatorbaum werden die einzelnen Teilbäume ausgezeichnet, die von einer bestimmten Zuweisung stammen. Verschiedene Variablen werden dabei zur besseren Übersicht farblich markiert, wie in Abbildung 3.1 ersichtlich ist. Johannes Kessler 35 KAPITEL 3. ÜBUNGSTOOL 1 2 3 4 5 6 7 8 9 10 11 12 S = sigma Semester > 8 Studenten Prof = sigma Rang >'C3' Professoren T = hoeren natural join Vorlesungen join gelesenVon = PersNr Prof pi MatrNr ( S natural join T ) Abbildung 3.1: Beispiel Abfrage in RA mit Zuweisungen und der Visualisierung im Operatorbaum des Programms. 3.1.4 Inline-Relationen Für einzelne Abfragen kann es hilfreich sein, neben den vorgegebenen Relationen eigene definieren zu können, die innerhalb eines Statements gültig sind. PostgreSQL bietet dafür z.B. die VALUES-Notation (siehe [Pos, Kapitel 7.7]), mit der konstante Tabellen“ definiert werden können. ” Mit dieser Notation kann sehr kompakt eine neue lokale Tabelle in der Abfrage definiert werden, wie am folgenden Beispiel ersichtlich ist: 1 2 3 4 5 6 36 select * from ( values ('a', 1, 6) , ('b', 2, 7) , ('c', 3, 8) , ('d', 4, 9) Johannes Kessler KAPITEL 3. ÜBUNGSTOOL 7 8 ) as R (a, b, c) where R.a != 'b' Ohne die VALUES-Notation kann man in z.B MySQL dasselbe auch folgendermaßen ausdrücken: 1 2 3 4 5 6 7 8 9 10 11 select * from ( select 'a' as a, 1 as b, 6 as c union select 'b', 2, 7 union select 'c', 3, 8 union select 'd', 4, 9 ) as R where R.a != 'b' Für diese Arbeit wurde die RA-Grammatik um ein vergleichbares Feature erweitert, das es erlaubt, innerhalb einer Abfrage neue Relationen zu definieren. Diese Inline-Relationen stellen einen gültigen RA-Ausdruck dar und können daher in jeder Operation verwendet werden. Die Notation lehnt sich an die Schema- und Tupelschreibweise in [KE11, Seite 72] an, wobei auf die eckigen Klammern verzichtet wird. Die Syntax soll am folgenden Beispiel erklärt werden: 1 2 3 4 5 { a:string , b:integer , X.c:date , word , 1, 1970 -01 -01 , 'long string ', 0.5, 1970 -01 -02 , } d null 'test ' Jede Inline-Relation wird von geschwungenen Klammern umgeben (Zeile 1 und 5). Die Daten sind zeilenweise strukturiert, wobei die erste Zeile (Zeile 2 im Beispiel) die Beschreibung des Schemas und alle weiteren Zeilen die Daten der einzelnen Tupel enthalten (Zeile 3 und 4). Die einzelnen Spalten können durch • Leerzeichen und Tabulatoren, • Kommas mit optionalen Leerzeichen und Tabulatoren oder • Strichpunkte mit optionalen Leerzeichen und Tabulatoren getrennt werden. Die Definition des Schemas erfolgt als Liste von Attributnamen, denen bei Bedarf der jeweilige Spaltentyp, mit Doppelpunkt getrennt, nachgestellt werden kann. Die explizite Nennung des Typs kann entfallen, solange der Typ eindeutig aus den Werten bestimmen lässt (siehe Spalte d Johannes Kessler 37 KAPITEL 3. ÜBUNGSTOOL in Zeile 2). Der Typ wird dabei vom ersten nicht null-Wert definiert. Bei jedem folgenden Wert anderen Typs wird eine Fehlermeldung ausgegeben. Gültige Typen sind number für integer- und float-Werte, string für Zeichenketten und date für Kalenderdaten. Dem Attributnamen kann ein mit Punkt getrennter Qualifizierer vorangestellt werden. Diese Syntax entspricht dadurch weitgehend der in der Literatur [KE11, Seite 72] und in Abbildung 2.1 verwendeten Notation eines Schemas. Die Werte der Tupel werden jeweils in einer Zeile notiert. Es gelten dabei dieselben Separatoren zur Trennung der Spalten. Einfache Wörter ([a-zA-Z]+), numerische Werte, die Konstante null oder Kalenderdaten in der Form YYYY-MM-DD werden ohne Anführungszeichen notiert. Längere oder komplexere Strings werden in einfachen Hochkommas eingeschlossen. Mit dieser Syntax kann in der Abfrage eine Relation erzeugt werden, die dem SQL-Beispiel entspricht: 1 2 3 4 5 6 7 8 sigma R.a != 'b' ({ R.a, R.b, R.c a, b, c, d, 1, 2, 3, 4, 6 7 8 9 }) Ein minimales Beispiel würde aus einer Relation mit einer Spalte und keinen Zeilen bestehen: {a: number } Der Typ muss dabei explizit angegeben werden, da keine Werte für eine Typbestimmung vorhanden sind. 3.1.5 Präzedenz Eine Operator-Präzedenz, wie sie in Abschnitt 2.5 definiert wurde, kann in einer PEG direkt abgebildet werden. Für die Grammatik des Übungstools wurden die Präzedenzregeln sowohl für die logischen Operatoren ^, ‘ und _, als auch für die Operatoren der relationalen Algebra umgesetzt. Die Klammerung der Operanden ist somit optional und kann in den meisten Fällen entfallen. Durch eine explizite Klammersetzung kann eine beliebige Auswertungsreihenfolge erzwungen werden, wie in Beispiel 3.3 anhand der Projektion gezeigt wird. Im Übungstool ist die gewählte Ausführungsreihenfolge nach der Ausführung sofort im Operatorbaum ersichtlich und die eingegebene Abfrage wird zusätzlich vollgeklammert angezeigt. Dadurch wird die Über- 38 Johannes Kessler KAPITEL 3. ÜBUNGSTOOL prüfung erleichtert, ob die gewählte Ausführungsreihenfolge mit der gewünschten übereinstimmt. 1 π A.Name , P.Name ( 2 ρ A Assistenten 3 ⨝ P. PersNr =Boss 4 σ Rang >'C3 ' _ Rangď'C2 ' 5 ρ P Professoren 6 ) Beispiel 3.3: Abfrage mit minimaler Klammersetzung und Operatorbaumdarstellung. 3.1.6 Plaintext Notation Alternativ zur klassischen Notation, die in Abschnitt 2.2 vorgestellt wurde, wird hier eine alternative Schreibweise eingeführt, die keine Sonderzeichen verwendet und dadurch eine möglichst komfortable und schnelle Eingabe ermöglichen soll. Es ist dadurch möglich, einen Ausdruck in relationaler Algebra als Plaintext zu notieren und ihn in dieser Form auch problemlos abzuspeichern oder in Dokumente einzubetten. Die griechischen Buchstaben werden dabei ausgeschrieben. Für Sonderzeichen wie ⟕“ wird eine alternative Schreibweise einge” führt, die sich an den SQL-Bezeichnern orientiert, um keine neuen Namen einführen zu müssen. Die zwei alternativen Schreibweisen können nach Belieben gemischt verwendet werden. In Tabelle 3.2 sind die alternativen Notationen den semantisch äquivalenten klassischen Notationen gegenübergestellt. Ausdrücke in eckigen Klammern sind optional. Die Klammerung der Relationen R und S dient nur der Veranschaulichung. Johannes Kessler 39 KAPITEL 3. ÜBUNGSTOOL klassische Notation σaąb (R) πa,b (R) ρX (R) ρxÐa,yÐb (R) ρaÑx,bÑy (R) RXS RYS R´S RzS R÷S R⨯S R ⨝ a=b^a=c S R⨝S R ⟕a=b_a=c S R ⟖a=b_a=c S R ⟖a=b_a=c S R⋉S R⋊S R◁S alternative Notation sigma a > b ( R ) pi a, b ( R ) rho X ( R ) rho x <- a, x <- b ( R ) rho a -> x, a -> x ( R ) R union S R intersect S R - S R \ S R / S R cross join S R x S R [inner] join a=b and a=c S R [natural] join S R left [outer] join a=b or a=c S R right [outer] join a=b or a=c S R full [outer] join a=b or a=c S R left semi join S R right semi join S R anti [semi] join S Tabelle 3.2: Plaintext Notationen der RA-Operatoren. Bei boolschen Ausdrücken für Bedingungen wird dieselbe Notation wie in SQL verwendet: Die logischen Operatoren and“, or“ und !“, und ” ” ” Vergleiche mit =, >=, <=, !=, < und >. Als Trennzeichen zwischen den einzelnen Tokens sind Leerzeichen, Tabulatoren und Zeilenumbrüche definiert. Dadurch kann ein großes Statement auch mit Einrückungen formatiert geschrieben werden. Das Statement 1 2 3 4 5 6 pi Name , Rang sigma p. PersNr >= 2130 ( rho p Professoren join gelesenVon = PersNr Vorlesungen ) ist somit semantisch äquivalent zu πN ame,Rang (σp.P ersN rě2130 (ρp P rof essoren ⨝ V orlesungen)) und sollte damit gleich komfortabel zu schreiben sein, wie dieselbe Abfrage als SQL Statement: 40 Johannes Kessler KAPITEL 3. ÜBUNGSTOOL 1 2 3 4 select distinct Name , Rang from Professoren as p inner join Vorlesungen on gelesenVon = PersNr where p. PersNr >= 2130 3.1.7 SQL Der Parser für SQL wurde mit PEG.js (siehe Abschnitt 3.1.1) umgesetzt. Er bietet die Möglichkeit, einfache SQL-SELECT-Statements zu formulieren, die in relationale Algebra übersetzt und ausgeführt werden. Eine Unterstützung für DML-Statements wie INSERT oder UPDATE ist nicht vorgesehen. Die unterstützte Syntax ist in einigen Punkten wie z.B. den Kommentaren an die SQL-Syntax von MySQL8 und PostgreSQL9 angelehnt. Die unterstützten Features sollen hier an mehreren kleinen Beispielen erklärt werden: Alle Schlüsselwörter sind nicht case-sensitiv und können daher auch klein geschrieben werden. Für den SELECT-Teil werden einerseits * oder eine Liste mit Spaltennamen in der Form name“ oder X.name“ unterstützt. X ist hierbei der Kurz” ” bezeichner einer Tabelle oder Unterabfrage. Das Schlüsselwort distinct wird zwingend verlangt, da die Elimination von Duplikaten in SQL nicht optional ist. In der relationalen Algebra können Relationen jedoch keine Duplikate enthalten. 1 2 SELECT DISTINCT * FROM Tabellenname Im FROM-Teil können Tabellennamen oder nicht korrelierte Substatements stehen. Jeder Tabelle kann mit as X ein Kurzbezeichner zugewiesen werden, wobei X für einen beliebigen Bezeichner steht. Bei Substatements ist dies obligatorisch. Nicht korreliert bedeutet, dass im Substatement nicht auf Daten der außen liegenden Statements zugegriffen werden kann. 8 http://dev.mysql.com/doc/refman/5.7/en/select.html, zuletzt besucht am 29.04.2014 9 http://www.postgresql.org/docs/9.3/static/sql-select.html, zuletzt besucht am 29.04.2014 Johannes Kessler 41 KAPITEL 3. ÜBUNGSTOOL 1 2 3 4 5 6 7 8 9 10 11 12 13 SELECT DISTINCT * FROM Tabelle1 , Tabelle2 as t2 , ( SELECT DISTINCT * FROM Tabelle3 ) as t3 inner join Tabelle4 as t4 on t4.a = t2.a natural join Tabelle5 inner join Tabelle6 natural left outer join Tabelle8 as t8 on t8.a = t2.a left outer join Tabelle9 natural right outer join ( select * from Tabelle10 ) as t10 Zu joinende Tabellen können entweder, wie in Zeile 2 als Liste hinter FROM aufgelistet werden oder, wie ab Zeile 6 dargestellt ist, explizit aufgeführt werden. Hierbei werden für den inneren Natural-Join zwei alternative Schreibweisen unterstützt, wie in Zeile 6 und 7 zu sehen ist. Der Left-, Right- und Full-Outer-Join wird jeweils mit explizitem Joinkriterium unterstützt, das nach on angeführt wird. Weiters steht jeweils eine Natural-Variante zur Verfügung, bei der das Joinkriterium implizit gegeben ist. Im WHERE-Teil werden Vergleiche in der Form a OPERATOR b mit den Operatoren =, != oder <>, >, <, >=, <=, is null und is not null unterstützt. Die Operanden a und b stehen hierbei für beliebige Spaltennamen oder Literale. Vergleiche können mit and und or verknüpft werden, die Negation geklammerter Ausdrücke mit ! wird unterstützt. Literale haben die Typen String, Number oder Date. Null kann als null oder NULL geschrieben werden. Strings werden in einfachen Hochkommas (z.B. 'text') notiert. Numerische Werte sind entweder ganzzahlig mit optionalem Vorzeichen in der Form (-?[0-9]+) z.B. 42“ oder Float Werte wie -42.0“, die durch ” ” folgenden regulären Ausdruck (-?[0-9]+.[0-9]+) beschrieben werden können. Datumswerte werden in der Form DATE('YYYY-MM-DD') notiert, wobei YYYY für das Jahr, MM für den Monat und DD für den Tag stehen. 1 2 3 4 SELECT DISTINCT * FROM Tabellenname WHERE a >10 and !(b <> '' or c is not null) ORDER BY a, b asc , 3 desc , a, b Das Sortierten der Ausgabe ist mit ORDER BY möglich. Dem Schlüsselwort folgt eine durch Kommas getrennte Liste mit Spaltennamen oder Spalten-Indizes. Jeder Eintrag kann durch asc oder desc ergänzt werden, um die Sortierrichtung anzugeben. Ohne explizite Angabe wird aufsteigend sortiert (asc). Eine Gruppierung ist mit GROUP BY möglich, wobei hier eine Liste der Spalten angegeben wird, nach denen gruppiert werden soll. 42 Johannes Kessler KAPITEL 3. ÜBUNGSTOOL Für die Aggregation können alle in Abschnitt 2.2.17 beschriebenen Funktionen verwendet werden. Für jede Aggregationsspalte muss mit as ein Name angegeben werden. In der HAVING-Klausel können, analog zur WHERE-Klausel, weitere Einschränkungen formuliert werden. Aggregationsspalten werden dabei über den neuen Bezeichner angesprochen. 1 2 3 4 5 6 SELECT DISTINCT a, b, COUNT (*) as anzahl , SUM(d) as summe FROM Tabellenname GROUP BY a, b HAVING summe > 100 ORDER BY 4 desc LIMIT 10 OFFSET 0 Wie bei PostgreSQL [Pos, Kapitel 7.6] kann durch LIMIT x OFFSET y oder LIMIT x eine vertikale Partitionierung vorgenommen werden. Es werden dabei die ersten x Zeilen ab der Zeile mit dem Index y ausgegeben. Um die Anzahl der Zeilen nicht zu limitieren, kann statt der Zeilenanzahl x das Schlüsselwort ALL verwendet werden. Ohne Angabe eines Offsets wird ab der ersten Zeile gezählt, was der Angabe LIMIT x OFFSET 0 entspricht. Die Schlüsselwörter UNION und INTERSECT stehen zur Verfügung, um die Vereinigung bzw. die Schnittmenge zweier Abfragen zu bilden. 3.2 Berechnung Die Berechnung der RA erfolgt ausschließlich clientseitig und wurde in JavaScript implementiert. Entgegen der RA-Theorie werden hier keine Mengen von Tupeln, sondern, ähnlich wie in relationalen Datenbanken, Multimengen in Form von zweidimensionalen Arrays von Werten als Basis verwendet. Dies hat den Vorteil, dass die Tupel eine definierte Ordnung besitzen. Duplikate werden vor der Ausgabe unter Beibehaltung der Reihenfolge eliminiert. Ziel dieser Arbeit war nicht, möglichst schnelle Algorithmen zu implementieren, sondern den Fokus auf den Übungscharakter des Programms zu legen. Es wurden daher oft langsamere Algorithmen implementiert, die für den User jedoch noch Vorteile wie das Erhalten einer bestimmten Reihenfolge bieten. Die Ausführungsgeschwindigkeit ist für kleine Tabellen und sinnvolle Abfragen, wie Sie für Übungen und Beispiele verwendet werden, ausreichend. So wird die Abfrage in Beispiel 3.4, die auf den Daten aus [KE11] basiert, in Google Chrome 35 und Mozilla Firefox 28 in ca 2 bis 4 Millisekunden ausgeführt10 . Bei kleinen Ergebnistabellen dauert die Darstellung als Tabelle länger als die eigentliche Berechnung der Daten. 10 Teststyem: Intel(R) Core(TM) i5 CPU M 520 mit 2.40GHz Johannes Kessler 43 KAPITEL 3. ÜBUNGSTOOL 1 2 3 4 5 6 7 8 9 10 11 12 13 tau [1], [2], [3] pi S.Name , S.Semester , P.Name ( ( Vorlesungen natural join ( rho S Studenten natural join rho H hoeren ) ) join gelesenVon = PersNr rho P Professoren ) Beispiel 3.4: Abfrage in relationaler Algebra. Alle RA-Operatoren wurden jeweils so umgesetzt, dass die Reihenfolge der Tupel der Argumentrelationen erhalten bleibt. Einer der einfachsten Algorithmen, einen Join auszuführen, ist der Nested-Loop-Join. Dieser wird in Datenbanksystemen, wenn möglich, durch schnellere Algorithmen ersetzt, da er eine Komplexität von O(|R| ˚ |S|) besitzt. Der Nested-Loop-Join (Beispiel 3.5) hat jedoch die Eigenschaft, dass das Ergebnis unabhängig von den Werten immer dieselbe leicht nachvollziehbare Struktur aufweist und auch Beispiele oft in dieser Form angegeben werden (z.B. Abbildung 2.14 [GMUW09, Seite 44], Abbildung 2.16 [GMUW09, Seite 46] und Abbildungen [KE11, Seite 88 und 89]). Ein Beispiel für einen Join-Algorithmus, bei dem die Reihenfolge nicht erhalten bleibt, ist der Hash-Join [GMUW09, Seite 734-738]. Dieser besitzt zwar eine durchschnittliche Laufzeit von O(|R|+|S|), die Tupel der Relationen werden jedoch über die Hashwerte der Join-Attribute gejoint. Dadurch ist die Reihenfolge der Tupel in der Ergebnisrelation von den Daten der Join-Attribute und der gewählten Hashfunktion abhängig. 1 2 3 4 5 6 for(r in R){ for(s in S){ if(r.a == s.a) // => [r, s] zum Ergebnis hinzufügen } } Beispiel 3.5: Nested-Loop-Join der Operation R ⨝ r.a=s.a S als Pseudocode. 44 Johannes Kessler KAPITEL 3. ÜBUNGSTOOL Aus diesem Grund wird für alle Join Operatoren der Nested-Loop-Join verwendet. Die Berechnung des Ergebnisses erfolgt, ausgehend vom Syntaxbaum des Parsers, bei dem verwendete Variablen bereits ersetzt wurden (siehe Abschnitt 3.1.3), in drei Schritten: Übersetzung, Überprüfung und die eigentliche Berechnung. Bei der Übersetzung wird anhand des Syntaxbaums (siehe Abschnitt 3.1.1) rekursiv ein Objekt für jede Operation erzeugt. Die Operanden jeder Operation sind wiederum Objekte der jeweiligen Operation und werden als Argument übergeben. Die verwendeten benannten Relationen werden in diesem Schritt aufgelöst, indem nach entsprechenden Relationen in der aktuell gewählten Gruppe gesucht wird. Nach dem Mapping steht der vollständige Operatorbaum zur Weiterverarbeitung zur Verfügung. Beim Wurzelobjekt dieses Operatorbaums wird im nächsten Schritt die check“-Funktion aufgerufen, die das Schema der jeweiligen Operation ” berechnet und eine semantische Prüfung vornimmt. Diese Funktion wird rekursiv für alle Kindelemente aufgerufen, da die Berechnung des Schemas eines Operators von den Schemata der Argumente abhängt. Die eigentliche Berechnung erfolgt in einem separaten Schritt. Die Basisfälle sind wiederum die Relationen, von denen ausgehend das Ergebnis bottom-up berechnet wird. SQL Die Berechnung von SQL-Statements erfolgt indirekt durch eine Übersetzung in relationale Algebra. Es wird ausgehend vom SQL-Syntaxbaum des Parsers ein RAOperatorbaum erzeugt. Ab diesem Zeitpunkt findet keine Unterscheidung mehr zwischen den beiden Sprachen statt. Die Übersetzung eines SQL-Statements in relationale Algebra soll exemplarisch an Beispiel 3.6 erklärt werden. Johannes Kessler 45 KAPITEL 3. ÜBUNGSTOOL 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 select distinct Titel as Vorlesungsname , Name from ( select distinct Titel , Name , SWS from Studenten as st natural join hoeren as h inner join Vorlesungen on h. VorlNr = Vorlesungen . VorlNr union select distinct Titel , Name , SWS from Vorlesungen , Professoren where gelesenVon = PersNr ) as t where SWS >= 3 order by 1, 2 desc Beispiel 3.6: Abfrage in SQL. Da die relationale Algebra prozedural aufgebaut ist, wird hier von innen nach außen vorgegangen. Im Programm ist dies einfach durch Rekursion abbildbar. Zuerst wird das Statement von Zeile 3 bis 6 übersetzt. Der Ausgangspunkt ist hierbei die Relation Studenten, welcher ein neuer Qualifizierer st zugewiesen wird. ρ st Studenten Dieser Ausdruck wird mit einem Natural-Join mit der Relation hoeren verknüpft, welcher der Kurzbezeichner h zugewiesen wird. (ρ st Studenten ) ⨝ (ρ h hoeren ) In Zeile 6 wird mit der Relation Vorlesungen gejoint. Einer Relation, der kein expliziter Kurzbezeichner zugewiesen wird, wird automatisch ein Kurzbezeichner zugewiesen, der dem Relationsnamen entspricht. Dies stellt sicher, dass die Spalten als Tabellenname.Spaltenname ansprechbar sind: ( (ρ st Studenten ) ⨝ (ρ h hoeren ) ) ⨝ h. VorlNr = Vorlesungen . VorlNr ( Vorlesungen ) Der SELECT-Teil des Statements entspricht in der RA einer Projektion. Das Schlüsselwort distinct wird an dieser Stelle zwingend benötigt, da die Duplikateneliminierung in SQL optional ist. Damit kann das Statement von Zeile 3 bis 6 in den folgenden RA-Ausdruck übersetzt werden: π Titel , Name , SWS ( ( (ρ st Studenten ) ⨝ (ρ h hoeren ) 46 Johannes Kessler KAPITEL 3. ÜBUNGSTOOL ) ⨝ h. VorlNr = Vorlesungen . VorlNr ( Vorlesungen ) ) Im Statement von Zeile 10-12 wird die ältere Join-Syntax verwendet. Hierbei wird zuerst das Kreuzprodukt der Relationen Vorlesungen und Professoren gebildet und darauf die Selektion ausgeführt. Der select-Teil wird, wie vorher, durch die Projektion abgebildet. π Titel , Name , SWS ( σ gelesenVon = PersNr ( Vorlesungen ⨯ Professoren ) ) Die Union-Operation aus SQL ist äquivalent zur Vereinigung in der relationalen Algebra (siehe Abschnitt 2.2.4). Somit können die Zeilen 3 bis 12 einfach zur folgenden Abfrage zusammengefasst werden: ( π Titel , Name , SWS ( ( (ρ st Studenten ) ⨝ (ρ h hoeren ) ) ⨝ h. VorlNr = Vorlesungen . VorlNr ( Vorlesungen ) ) ) Y ( π Titel , Name , SWS ( σ gelesenVon = PersNr ( Vorlesungen ⨯ Professoren ) ) ) Im äußeren Statement wird das vereinigte Statement (Zeile 3 bis 12) als Substatement verwendet, welchem der Bezeichner t zugewiesen wird. Ein nicht korreliertes Substatement11 wird in der RA einfach als Operand der jeweiligen Operation abgebildet. Eine Übersetzung von korrelierten Unterabfragen wäre wesentlich aufwendiger und wird sowohl in der Literatur, z.B. [KE11], als auch in Vorlesungen selten behandelt. Daher wurde auf die Unterstützung von korrelierten Unterabfragen verzichtet. Der WHERE-Teil entspricht einer einfachen Selektion mit der entsprechenden Bedingung. Im SELECT-Teil in Zeile 1 wird der Spalte Titel ein neuer Name zugewiesen, was in der Verwendung der Umbenennung ρ resultiert. Order-by kann durch die Erweiterung der relationalen Algebra (siehe Abschnitt 2.2.15) mit dem τ -Operator abgebildet werden. Das komplette Statement kann somit wie folgt in relationaler Algebra dargestellt werden: 11 Korreliert bedeutet, dass innerhalb des Substatements auf Daten der umschließenden Abfrage referenziert werden kann. Johannes Kessler 47 KAPITEL 3. ÜBUNGSTOOL τ [1] , [2] desc (π Titel , Name ( σ SWSě3 (ρ t ( ( π Titel , Name , SWS ( ( (ρ st Studenten ) ⨝ (ρ h hoeren ) ) ⨝ h. VorlNr = Vorlesungen . VorlNr ( Vorlesungen ) ) ) Y ( π Titel , Name , SWS ( σ gelesenVon = PersNr ( Vorlesungen ⨯ Professoren ) ) ) )) )) Das SQL-Statement 1 2 3 4 5 6 7 SELECT DISTINCT a, b, COUNT (*) as anzahl FROM R WHERE a >= 1 GROUP BY a, b HAVING anzahl > 2 ORDER BY 3 desc LIMIT 1 OFFSET 1 kann folgendermaßen in relationale Algebra übersetzt werden: π a, b, anzahl ( σ ROWNUMą1 ^ ROWNUMď2 ( π a, b, anzahl , ROWNUM ( τ [3] desc ( π a, b, anzahl ( σ anzahl >2 ( γ a, b ; COUNT (*)Ñanzahl ( σ aě1 ( R ) ))))))) Die Gruppierung in Zeile 4 wird dabei durch den Gruppierungsoperator γ (siehe Abschnitt 2.2.17) abgebildet. Dabei wird nach allen in GROUP BY angegebenen Spalten gruppiert. Die Aggregationsfunktionen (im Beispiel COUNT(*)) werden in SQL im SELECT-Teil definiert. Die HAVING-Klausel in Zeile 5 entspricht einer Selektion, die nach γ ausgeführt wird. Die vertikale Partitionierung mit LIMIT 1 OFFSET 1 erfolgt in der relationalen Algebra durch eine Selektion mit dem Zeilenindex ROWNUM, der durch die erweiterte Projektion (siehe Abschnitt 2.2.16) zur Verfügung gestellt wird. Die Übersetzung von RA in SQL erfolgt automatisch im Hintergrund, um ein äquivalentes Statement in relationaler Algebra zu erzeugen (siehe Abbildung 3.2). Die Übersetzung soll den Benutzern helfen, einerseits 48 Johannes Kessler KAPITEL 3. ÜBUNGSTOOL die relationale Algebra schneller zu erlernen, wenn schon gewisse SQL Vorkenntnisse vorhanden sind, und anderseits einen Einblick zu erhalten, wie eine SQL-Abfrage in relationale Algebra übersetzt und ausgeführt werden kann. Abbildung 3.2: Anwendung mit SQL-Statement aus Abschnitt 3.2. 3.3 Server Dieses Kapitel beschreibt die Serverkomponente, welche die Tabellen zur Verfügung stellt, die für die RA- und SQL-Statements verwendet werden. Eine Aufgabe ist eine Zusammenstellung von einer oder mehreren zuJohannes Kessler 49 KAPITEL 3. ÜBUNGSTOOL sammengehörenden Tabellen zu einer Gruppe. Diese kann mit zusätzlichen Informationen wie eine Referenz zum Übungsblatt und einem optionalen Sichtbarkeitszeitraum versehen werden. Übungsleiter sollen in der Lage sein, neue Aufgaben anzulegen und dabei vorhandene (MySQL) Tabellen wiederzuverwenden, die den Benutzern beispielsweise über Frontends wie phpMyAdmin zur Verfügung gestellt werden, um SQL Abfragen ausführen zu können. Zur einfachen Weiterverarbeitung in JavaScript werden die Daten direkt als JSON-codiert ausgegeben. Eine Gruppe hat folgende Struktur: • eine eindeutige numerische ID, um die Tabellen nachzuladen, • einen Gruppennamen, wie er im Client angezeigt wird, z.B. Tu” torial Exercise 1 - 2014“, • eine Beschreibung mit weiteren Informationen zur Übung, • einen optionalen Zeitraum zur Steuerung der Sichtbarkeit, • eine Liste aller Tabellen der Gruppe mit – einer numerischen ID, – dem Namen der Tabelle, wie er im Client angezeigt wird und – den Spaltennamen und -typen der jeweiligen Tabellen. 50 Johannes Kessler KAPITEL 3. ÜBUNGSTOOL 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 {"2": { " groupId ": 2, " groupName ": " DatabaseSystems Lecture ", " groupDesc ": " Tables from and for the lecture <a href =\" http :\/\/ dbis - informatik .uibk.ac.at \/249 -0 -VO Datenbanksysteme .html \"> Databases : Foundations , Data Models and System Concepts - University of Innsbruck <\/a> chapter 3", " online_until ": null , " tables ": [ { " tableId ": 0, " tableName ": "R", " columnNames ": ["a", "b", "c"], " columnTypes ": [" number ", " string ", " string "] }, { " tableId ": 1, " tableName ": "S", " columnNames ": ["b", "d"], " columnTypes ": [" string ", " number "] }, { " tableId ": 2, " tableName ": "T", " columnNames ": ["b", "d"], " columnTypes ": [" string ", " number "] } ] } } Beispiel 3.7: Antwort auf eine Abfrage aller Gruppen. Die Serverkomponente wurde in PHP implementiert und stellt die Daten über eine einfache REST-Schnittstelle zur Verfügung. Es gibt zwei einfache Verwaltungstabellen, ra_group und ra_table, in denen die Informationen zu den Gruppen und deren Tabellen gespeichert sind. Die Abfrage GET index.php/groups wird verwendet, um die Spezifikation aller Gruppen und deren Tabellen zu laden. Die Namen und Typen der Spalten der einzelnen Tabellen werden aus der MySQL-Tabelle INFORMATION_SCHEMA.COLUMNS 12 geladen, welche die Datentypen der Spalten jeder Tabelle enthält (siehe Beispiel 3.7). Die Abfrage GET index.php/tables/X dient dazu, die Daten der Tabellen der Gruppe mit der group-id X zu laden (siehe Beispiel 3.8). 12 http://dev.mysql.com/doc/refman/5.5/en/columns-table.html - 2014 Johannes Kessler 51 KAPITEL 3. ÜBUNGSTOOL 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 [ [ ["1", "a", "d"], ["3","c","c"], ["4","d","f"], ["5","d","b"], ["6","e","f"] ], [ ["a","100"], ["b","300"], ["c","400"], ["d","200"], ["e","150"] ], [ ["a","100"], ["d","200"], ["f","400"], ["g","120"] ] ] Beispiel 3.8: Antwort auf eine Abfrage index.php/tables/2. 3.4 Geteilte Tabellen In Abschnitt 3.3 wurde eine Möglichkeit vorgestellt, den Usern Gruppen von Tabellen für Abfragen zur Verfügung zu stellen. Der Fokus liegt dabei auf einer einfachen Wiederverwendung von vorhanden Datensätzen und Tabellen in einer Datenbank. Somit können die Daten leicht sowohl über das relationale Algebra Übungstool als auch z.B. per phpMyAdmin zur Verfügung gestellt werden. Eine Alternative dazu stellt das Laden der Daten von externen Quellen dar. Das Ziel ist hierbei, eine einfache Möglichkeit zu schaffen, Tabellen für Abfragen zu veröffentlichen und auszutauschen. Dies bietet unter anderem die Möglichkeit, dass Benutzer selbst Tabellen definieren und diese mit anderen teilen können. Eine Gruppe von Tabellen besteht aus dem Namen der Gruppe, einer optionalen Beschreibung und einer oder mehreren Tabellendefinitionen. Für die Definition einer Gruppe wurde ein einfaches Format definiert, das es erlaubt, ein oder mehrere Gruppen als Klartext zu beschreiben. Die verwendete Syntax zur Definition der Tabellen entspricht der in Abschnitt 3.1.1 vorgestellten Syntax für Abfragen in relationaler Algebra. Tabellen werden dazu als Zuweisungen (siehe Abschnitt 3.1.3) abgebildet. 52 Johannes Kessler KAPITEL 3. ÜBUNGSTOOL Der Gruppenname und die optionale Beschreibung werden am Beginn der Datei notiert. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 group : Name der Gruppe description [[ Beschreibung der Gruppe über <b>mehrer </b> Zeilen ]] TabelleA = { a, b 1, a 2, b 3, c } TabelleB = { a, d 1, 0.5 2, -1 4, 42 } -- Tabellendefinition als komplexer Ausdruck TabelleC = (pi a TabelleB ) cross join { e 1970 -01 -01 2038 -01 -19 } Jede Headerdeklartation beginnt mit dem Headernamen gefolgt von einem Doppelpunkt bei einzeiligen Text (Zeile 1) oder [[ bei mehrzeiligem Text. Mehrzeilige Header werden durch ]] beendet das innerhalb des Texts als \]] escaped werden kann. Derzeit sind die Header group für den Namen der Gruppe und description für deren Beschreibung definiert. Im Beschreibungstext kann hierbei mit beliebigem HTML ausgezeichnet werden, um beispielsweise Hyperlinks auf weiterführende Literatur setzen zu können. Die Definition der Tabellen erfolgt durch eine Liste von Zuweisungen, wie sie auch in einer Abfrage verwendet werden können. Der Variablenname entspricht hierbei dem Tabellennamen in der Gruppe. Die Tabelle wird durch den zugewiesenen Ausdruck definiert. Der Ausdruck muss dabei ein gültiger RA-Ausdruck sein und ist im einfachsten Fall eine Inline-Relation (siehe Abschnitt 3.1.4). Es ist möglich, innerhalb eines Ausdrucks eine andere Relation der selben Gruppe zu verwenden. Hierbei gelten dieselben Regeln wie für die Verwendung von Zuweisungen (Abschnitt 3.1.3). Die Namen und Typen der Spalten ergeben sich aus dem Schema der Ausdrücke. Der Qualifizierer einer Tabelle wird beim Laden für alle Spalten automatisch auf den Tabellennamen gesetzt. Johannes Kessler 53 KAPITEL 3. ÜBUNGSTOOL Innerhalb einer Datei können mehrere Gruppen untereinander definiert werden, wobei jede mit einem eigenen Header beginnt. Dieses Format wird auch applikationsintern verwendet, um alle Gruppen zu laden, die nicht über die Serverschnittstelle aus der Datenbank geladen werden. Als Quelle wird derzeit Github Gist13 unterstützt. Github Gist ist eine Plattform, auf der Code-Snippets einfach veröffentlicht und geteilt werden können. Jeder Gist ist dabei ein vollstädiges Git-Repository. Gists können sowohl anonym als auch als registrierter Github User erstellt werden und erhalten jeweils eine eindeutige ID. Über diese ID können die Gruppendefinitionen im Übungstool geladen werden. Dabei wird die Applikation direkt mit dem Querystring ?data=gist:ID aufgerufen. Die Url http://example.com/?data=gist:ac267b9cc810ac5f20e2 lädt somit automatisch die Tabellengruppe, die im Gist mit der ID ac267b9cc810ac5f20e2 definiert wurde. 13 https://gist.github.com/, zuletzt besucht am 29.04.2014 54 Johannes Kessler Kapitel 4 Grafische Benutzeroberfläche Die grafische Benutzeroberfläche des Übungstools ist komplett webbasiert und wurde mit HTML5 umgesetzt. Beim Start der Anwendung wird die Gruppenübersicht vom Server gladen. Die Tabellen werden bei der Auswahl einer Gruppe per AJAX nachgeladen. Sämtliche Berechnungen laufen clientseitig ab. Dies ermöglicht ein komfortables Arbeiten ohne Rücksichtnahme auf die aktuelle Reaktionszeit des Servers. Wie in Abbildung 4.1 auf Seite 56 zu sehen ist, besteht die Oberfläche aus den folgenden Komponenten (von links oben nach rechts unten): 1. einem Dropdownmenü zur Auswahl der Tabellengruppe 2. einer Liste mit Tabellen und deren Spalten 3. dem Editor mit Toolbar (siehe Abschnitt 4.1) 4. einer Operatorbaumdarstellung des Statements (siehe Abschnitt 4.2) 5. der RA-Formel jenes Teils der Formel, welcher berechnet wurde 6. der Anzeige der berechneten Daten als Tabelle Die Oberfläche wurde zu großen Teilen mittels Bootstrap1 gestaltet. Für die Interaktion mit dem DOM wird jQuery2 verwendet. 1 2 http://getbootstrap.com/, zuletzt besucht am 29.04.2014 http://jquery.com/, zuletzt besucht am 29.04.2014 55 KAPITEL 4. GRAFISCHE BENUTZEROBERFLÄCHE Abbildung 4.1: Editor mit Toolbar im Modus für relationale Algebra. 4.1 Editor Der Editor ist eine der Hauptkomponenten der Applikation und dient neben der Texteingabe auch der Anzeige von Fehlermeldungen. Die Editorkomponente wurde mit CodeMirror 3 umgesetzt3 . CodeMirror ist ein freier webbasierter Editor, der unter der MIT-Lizenz steht und umfangreiche Erweiterungsmöglichkeiten bietet. Die Eingabe einer Abfrage kann im Übungstool sowohl in SQL als auch in relationaler Algebra erfolgen. Für die relationale Algebra steht eine umfangreiche Toolbar zur Verfügung, über die Sonderzeichen der Operatoren komfortabel eingegeben werden können. Wie in Abbildung 4.2 zu sehen ist, wird für jede Operation zusätzlich ein kurzes Beispiel angezeigt, das die Verwendung des 3 http://codemirror.net/, zuletzt besucht am 29.04.2014 56 Johannes Kessler KAPITEL 4. GRAFISCHE BENUTZEROBERFLÄCHE Operators illustriert. . + . . oder der Sprachübergreifend kann die aktuelle Abfrage mit strg execute“-Schaltfläche ausgeführt werden. Über dieselbe Schaltfläche ” kann, sobald Text innerhalb des Editors markiert ist, dieser Teil der Abfrage ausgeführt werden. Dies ist auch über die Tastatur mit . + .. + . . möglich. strg Abbildung 4.2: Editor mit Toolbar im Modus für relationale Algebra. 4.1.1 Syntax-Highlighting Für die relationale Algebra wurde ein eigener mode4 definiert, der für das Syntax-Highlighting verwendet wird. Dieser besteht aus einem einfachen Lexer, der die Eingabe in einzelne Tokens aufteilt, und einer einfachen Erkennung für Schlüsselwörter, Strings, einzeilige Kommentare und Blockkommentare. Jedem Token wird in diesem Schritt ein Typ zugeordnet, der das Aussehen als CSS-Klasse definiert (siehe Abbildung 4.2 auf dieser Seite). Für das Syntax-Highlighting wird nicht der Parser aus Abschnitt 3.1.1 verwendet, da dieser nur dann einen Syntaxbaum erzeugt, wenn die gesamte Abfrage syntaktisch korrekt ist. Der Lexer besteht aus einer Funktion token und einem Zustandsobjekt. Die Funktion token wird von Codemirror selbständig aufgerufen, liest bis zum jeweils nächsten Token vom Stream und gibt den entsprechenden Typ zurück. Das Zustandsobjekt wird bei jedem Aufruf der Funktion token übergeben und enthält beispielsweise den Status, ob ein Blockkommentar geöffnet wurde. 4 http://codemirror.net/doc/manual.html#modeapi, zuletzt besucht am 29.04.2014 Johannes Kessler 57 KAPITEL 4. GRAFISCHE BENUTZEROBERFLÄCHE CodeMirror ruft die Funktion token dabei wärend der Eingabe selbständig für Teile des Texts auf. Dabei wird jeweils ein an dieser Position gültiges Zustandsobjekt übergeben. Dadurch wird vermieden, jeweils den gesamten Text neu parsen zu müssen. Ein mode für SQL ist in Codemirror bereits enthalten und musste daher nicht implementiert werden. 4.1.2 Fehlermeldungen Fehlermeldungen werden direkt im Editor angezeigt, wenn Informationen zur Position im Code zur Verfügung stehen (siehe Abbildung 4.3). Allgemeine Fehler, die nicht direkt auf eine bestimmte Textstelle bezogen werden können, werden unter dem Editor angezeigt. Abbildung 4.3: Anzeige von Fehlermeldungen im Editor. Die Überprüfung auf syntaktische und semantische Fehler erfolgt mithilfe des Lint-Addons5 während der Eingabe automatisch im Hintergrund. Dafür wird der komplette Text kurze Zeit nach der letzten Eingabe geparst, in RA übersetzt und dort die semantische Prüfung vorgenommen. Die Codepositionen werden bei den einzelnen Schritten, wenn möglich, weitergegeben, sodass auch semantische Fehler im Text entsprechend angezeigt werden können. 4.1.3 Autovervollständigung . + Leertaste . Die Autovervollständigung kann mit strg ausgelöst werden und bietet Vorschläge zur Vervollständigung des aktuellen Wortes an. Dazu stehen einerseits die Schlüsselwörter der aktuell ausgewählten Sprache als auch die Namen und Spaltennamen der verwendeten Gruppe von Tabellen zur Verfügung (siehe Abbildung 4.4). Bei jeder erfolgreichen Übersetzung in RA werden zusätzlich alle Spaltennamen der Schemata der Operatoren hinzugefügt. 5 http://codemirror.net/doc/manual.html#addon_lint, zuletzt besucht am 29.04.2014 58 Johannes Kessler KAPITEL 4. GRAFISCHE BENUTZEROBERFLÄCHE Abbildung 4.4: Autovervollständigung im Code-Editor. Durch diese Erweiterungen und die alternative Plaintext Syntax für die relationale Algebra können Abfragen sehr einfach formuliert und getestet werden, ohne dafür die Maus verwenden zu müssen. 4.2 Operatorbaum Für eine einfache Darstellung des ausgeführten Statements wird dieses im Übungstool als Operatorbaum dargestellt. Die Darstellung lehnt sich dabei an Darstellungen in der Literatur (z.B. [KE11, Seite 98] und [GMUW09, Seite 48]) an und wurde in Abschnitt 2.4 vorgestellt. Durch diese Darstellung kann die Ausführungsreihenfolge selbst bei komplexen Abfragen sehr leicht nachvollzogen werden. Der Baum dient weiters zur Steuerung der Anzeige von Zwischenergebnissen. Beim Ausführen wird jeweils die gesamte Abfrage ausgewertet und das Ergebnis tabellarisch angezeigt. Durch einen Klick auf einen Operator im Baum wird das Ergebnis des jeweiligen Teilbaums berechnet und angezeigt. Der entsprechende Knoten und dessen Kindelemente wird dabei optisch hervorgehoben. Durch dieses Feature ist es den Benutzern leicht möglich, die Berechnung der Abfrage in Einzelschritten nachzuvollziehen. Beim Mouseover über einen bestimmten Knoten werden Informationen zum jeweiligen Zwischenergebnis angezeigt. Hierbei werden einerseits das Schema der Relation als auch die maximale Anzahl der Zeilen6 angezeigt. Bei Natural-Joins wird zusätzlich angezeigt, über welche Spalten gejoint wird. Jede Verwendung einer durch eine Zuweisung entstandenen Variable (siehe Abschnitt 3.1.3) wird im Operatorbaum durch ein farbiges Label gekennzeichnet. Bei mehrfacher Verwendung derselben Variable erhält das Label jeweils die gleiche Farbe. 6 Zeilenanzahl vor der Duplikatenelimination Johannes Kessler 59 KAPITEL 4. GRAFISCHE BENUTZEROBERFLÄCHE In Abbildung 4.5 auf dieser Seite ist der Operatorbaum der folgenden Abfrage dargestellt: 1 2 3 4 5 6 7 8 9 10 11 12 S = rho S sigma Semester > 2 Studenten Prof = sigma Rang >'C3' Professoren T = hoeren natural join Vorlesungen join gelesenVon = PersNr Prof pi S.MatrNr , S.Name , Semester ( S join S. MatrNr = hoeren . MatrNr T ) Die Wurzelknoten der Teilbäume der Variablen S, T, und Prof sind jeweils farbig hervorgehoben. Das angezeigte Ergebnis wäre das des ersten Joins, welches jedoch in der Abbildung nicht mehr dargestellt ist. Abbildung 4.6 zeigt einen Ausschnitt desselben Baums beim Mouseover eines Natural-Joins. Abbildung 4.5: Operatorbaumdarstellung mit Variablen. 60 Johannes Kessler KAPITEL 4. GRAFISCHE BENUTZEROBERFLÄCHE Abbildung 4.6: Informationen beim Mouseover im Operatorbaum. 4.3 Font Das Übungstool ermöglicht es, Operatoren in RA-Ausdrücken mit den entsprechenden Sonderzeichen zu notieren (siehe Abschnitt 3.1.1). In Tabelle 4.1 auf Seite 63 werden dazu die entsprechenden Operatoren und deren Symbole aufgelistet. Um die Symbole jedoch im Browser darzustellen, muss ein Font zur Verfügung stehen, der Glyphen für alle verwendeten Sonderzeichen enthält. Freie Fonts, die entsprechende Glyphen enthalten, z.B. Free Sans, Free Serif, DejaVu Sans oder Asana-Math, sind mehrere hundert KB groß und daher für eine Webanwendung nicht wirklich geeignet. Auch sind nicht in jeder Font alle benötigten Symbole enthalten, wodurch ein inkonsistentes Aussehen entsteht, da Glyphen aus unterschiedlichen Schriftarten verwendet werden können, wie in Abbildung 4.7 auf der nächsten Seite ersichtlich ist. Um Umgebungen zu unterstützen, in denen kein entsprechender serifenloser Font zur Verfügung steht, und um größeren Einfluss auf das Aussehen der Weboberfläche zu erhalten, wurde aus bestehenden Fonts eine reduzierte Version erstellt, die Glyphen für alle Operatoren enthält, und nur ca 20 KB groß ist. Es wurden dazu Glyphen der Fonts FreeSans und FreeSerif verwendet. Teilweise wurden die Glyphen manuell angepasst. Für die Operatoren werden die in Tabelle 4.1 dargestellten Unicode Symbole verwendet. Johannes Kessler 61 KAPITEL 4. GRAFISCHE BENUTZEROBERFLÄCHE Abbildung 4.7: Editor mit inkonsistenter Sonderzeichendarstellung (Firefox 28 unter Ubuntu 14.04). Abbildung 4.8: Editor mit konsistenter Sonderzeichendarstellung (Firefox 28 unter Ubuntu 14.04). Durch den neuen Font kann browser- und betriebsystemübergreifend ein einheitliches Schriftbild im Editor gewährleistet werden, wie in Abbildung 4.8 dargestellt ist. 62 Johannes Kessler KAPITEL 4. GRAFISCHE BENUTZEROBERFLÄCHE Zeichen γ π σ ρ τ Ð Ñ Y X ÷ ⨯ ⨝ ⟕ ⟖ ⟗ ⋉ ⋊ ◁ ^ _ ‘ Y ‰ ď ě Bezeichnung greek small letter gamma greek small letter pi greek small letter sigma greek small letter rho greek small letter tau leftwards arrow rightwards arrow union intersection division sign vector or cross product join left outer join right outer join full outer join left normal factor semidirect product right normal factor semidirect product white right-pointing triangle logical and logical or circleplus xor not equal to less-than or equal to greater-than or equal to Position U+03B3 U+03C0 U+03C3 U+03C1 U+03C4 U+2190 U+2192 U+222A U+2229 U+00F7 U+2A2F U+2A1D U+27D5 U+27D6 U+27D7 U+22C9 U+22CA U+25B7 U+2227 U+2228 U+2295 U+22BB U+2260 U+2264 U+2265 Tabelle 4.1: Unicode Symbole der Operatoren. Johannes Kessler 63 Kapitel 5 Zusammenfassung In dieser Bachelorarbeit wurde ein Übungstool für relationale Algebra (RA) vorgestellt. Dazu wurden die relationale Algebra und ihre Operatoren unter Verwendung eines vollqualifizierten Attributnamens vorgestellt und eine Operatorpräzedenz definiert, die im Programm verwendet wurde. Das implementierte Übungsprogramm ist in der Lage, beliebige Abfragen in RA zu berechnen. Die Ergebnisse werden dabei tabellarisch dargestellt und die RA-Formel als Operatorbaum präsentiert. Der Operatorbaum dient außerdem zur Anzeige von Zusatzinformationen zur jeweiligen Operation. Es ist auch möglich, Zwischenergebnisse eines Teils der eingegebenen Abfrage berechnen und anzeigen zu lassen. Das Programm bietet weiters die Möglichkeit, Abfragen in SQL einzugeben. Diese werden automatisch in RA übersetzt und berechnet. Die für die Berechnung verwendeten Daten können in einer Datenbank zur Verfügung gestellt werden und mittels PHP vom Server geladen werden. Als Alternative besteht die Möglichkeit, die Daten aus öffentlichen Codesippets zu laden, die auf der Plattform Github Gist veröffentlicht wurden. Damit ist es für jeden Benutzer möglich, die Basisdaten für Berechnungen selbst anzulegen und mit anderen zu teilen. Für die Eingabe der RA-Statements wird eine entsprechende Syntax vorgestellt, die es ermöglicht, RA-Formeln in der klassischen“ Form ” fast unverändert schreiben zu können. Alternativ wird eine Operatorschreibweise eingeführt, welche auf die Verwendung von Sonderzeichen verzichtet und alternative Textbezeichner verwendet. Für die RA-Syntax werden mehrere Erweiterungen definiert, die es ermöglichen, innerhalb der Abfrage Kommentare, Zuweisungen von Variablen und konstante Relationen zu verwenden. Konstante Relationen bieten dabei eine einfache Möglichkeit, neue lokal gültige Relationen im Quelltext definieren zu können. Die Eingabe der Statements erfolgt in einem komfortablen Code-Editor, 65 KAPITEL 5. ZUSAMMENFASSUNG für den eine Autovervollständigung als auch Syntax-Highlighting zur Verfügung gestellt wird. Ausblick Das Übungstool unterstützt derzeit die Eingabe von Abfragen in relationaler Algebra und SQL. In [GMUW09, Seite 217] wird eine Erweiterung der Projektion beschrieben, die es erlaubt, Berechnungen mit den Tupelkomponenten vorzunehmen. Ein einfaches Beispiel dafür wäre die Summe zweier Spalten. Dies würde das Formulieren von komplexeren Abfragen mit arithmetischen Ausdrücken erlauben, wie sie in SQL möglich sind. Die Übersetzung von SQL bietet derzeit keine Unterstützung für korrelierte Unterabfragen, Abfragen mit Exists oder die Verwendung von Funktionen und arithmetischen Operationen. Meist werden in der Fachliteratur und in der Lehre neben der relationalen Algebra auch der Tupelkalkül und der Domänenkalkül eingeführt. Diese werden vom Übungstool jedoch derzeit nicht unterstützt. Hier wäre interessant, eine Plattform zu schaffen, die das Erlernen aller grundlegenden Abfragesprachen unterstützt. Dabei wäre jedoch zu evaluieren, ob der Ansatz der Übersetzung in relationale Algebra dabei das Verständnis erleichtert, oder ob eine alternative Darstellung hilfreicher wäre. 66 Johannes Kessler Literaturverzeichnis [AHV95] S. Abiteboul, R. Hull and V. Vianu: Foundations of Databases, Addison-Wesley, 1995. [Cod70] E. F. Codd: A Relational Model of Data for Large Shared Data Banks, Commun. ACM, volume 13(6), (1970), pages 377–387. [For04] B. Ford: Parsing Expression Grammars: A Recognitionbased Syntactic Foundation, SIGPLAN Not., volume 39(1), (2004), pages 111–122, URL http://doi.acm.org/10. 1145/982962.964011. [GMUW09] H. Garcia-Molina, J. D. Ullman and J. Widom: Database Systems - The Complete Book, Pearson Prentice Hall, New Jersey, 2nd edition, 2009. [KE11] A. Kemper and A. Eickler: Datenbanksysteme - Eine Einführung, Oldenbourg Verlag, München, 8. Auflage, 2011. [Maj14] D. Majda: PEG.js — Parser Generator for JavaScript, 2014, URL http://pegjs.majda.cz/documentation, [Online; Stand 29. April 2014]. [Mol09] L. Molkov: Relation Algebra Expression Evaluation, 2009, URL http://is.muni.cz/th/208197/fi_b/bc_thesis. pdf. [Pos] PostgreSQL Global Development Group: PostgreSQL 9.3.4 Documentation, URL http://www.postgresql.org/ docs/9.3/static/, [Online; Stand 29. April 2014]. [Ull04] J. Ullman: First Course in Database Systems, 2004, URL http://infolab.stanford.edu/~ullman/fcdb/slides. html, [Online; Stand 29. April 2014]. [Wik14a] Wikipedia: Relational algebra — Wikipedia, The Free Encyclopedia, 2014, URL http://en.wikipedia.org/w/index. 67 LITERATURVERZEICHNIS php?title=Relational_algebra&oldid=603628483, [Online; Stand 29. April 2014]. [Wik14b] 68 Wikipedia: Relationale Algebra — Wikipedia, Die freie Enzyklopädie, 2014, URL http://de.wikipedia.org/ w/index.php?title=Relationale_Algebra&oldid= 128441501, [Online; Stand 29. April 2014]. Johannes Kessler