Eidgenössische Technische Hochschule Zürich Swiss Federal Institute of Technology Zurich Institut für Informationssysteme Dr.C.Türker Objektrelationale, erweiterbare Datenbanken WS 0405 Übung 8 Aufgabe 1: Objektrelationales Oracle-SQL Beispiellösung Setzen Sie die Klassenhierarchie Artikel Klassen: Artikel, ArtikelSet, Lebensmittel, Haushaltswaren und die Klasse Katalog aus dem UML-Diagramm von Übung 1 mit Hilfe der objektrelationalen Erweiterungen von Oracle um. Verwenden Sie dabei Objekttypen-tabellen. Beispiellösung: Oracle unterstützt keine Subtabellen. Daher muss die UML-Klassenhierarchie auf einem anderen Weg auf Oracle-SQL abgebildet werden. Die folgende Lösung nutzt die Konzepte der Objekttypen, Subtypbildung und Substituierbarkeit, um die komplette Klassenhierarchie auf eine Objekttabelle abzubilden, wobei die einzelnen Klassen durch Objektsichten repräsentiert werden. Bei den Aggregationsbeziehungen wurden die Kardinalitäten vernachlässigt. CREATE TYPE BildKollektionsTyp AS TABLE OF BLOB; CREATE TYPE ArtikelTyp AS OBJECT Nummer CHAR12, Bezeichnung VARCHAR40, Preis DECIMAL12,2, Beschreibung VARCHAR2000, Bilder BildKollektionsTyp NOT FINAL; CREATE TYPE ArtikelKollektionsTyp AS TABLE OF REF ArtikelTyp; CREATE TYPE ArtikelSetTyp UNDER ArtikelTyp Artikel ArtikelKollektionsTyp, MEMBER FUNCTION AnzahlArtikel RETURN INTEGER FINAL; CREATE TYPE BODY ArtikelSetTyp AS MEMBER FUNCTION AnzahlArtikel RETURN INTEGER AS RETURN SELF.Artikel.COUNT; 1 CREATE TYPE LebensmittelTyp UNDER ArtikelTyp Gewicht DECIMAL10, Zusammensetzung VARCHAR400, MEMBER FUNCTION GewichtInKilo RETURN INTEGER FINAL; CREATE TYPE BODY LebensmittelTyp AS MEMBER FUNCTION GewichtInKilo RETURN INTEGER AS RETURN SELF.Gewicht 1000; CREATE TYPE HaushaltswarenTyp UNDER ArtikelTyp Garantie DATE, Farbe VARCHAR30 FINAL; CREATE TYPE KatalogTyp AS OBJECT Titel VARCHAR30, Jahr DECIMAL4, Sommer CHAR1, Artikel ArtikelKollektionsTyp, MEMBER FUNCTION AnzahlArtikel RETURN INTEGER NOT FINAL; CREATE TYPE BODY KatalogTyp AS MEMBER FUNCTION AnzahlArtikel RETURN INTEGER AS RETURN SELF.Artikel.COUNT; CREATE TABLE Katalog OF KatalogTyp PRIMARY KEYJahr, Sommer, Titel NOT NULL NESTED TABLE Artikel STORE AS KatalogArtikel; 2
CREATE TABLE Artikel OF ArtikelTyp Nummer PRIMARY KEY, Bezeichnung NOT NULL NESTED TABLE Bilder STORE AS ArtikelBilder; CREATE VIEW ArtikelSet OF ArtikelSetTyp AS SELECT TREATVALUEa AS ArtikelSetTyp WHERE VALUEa IS OF ONLY ArtikelSetTyp; CREATE VIEW AllgemeineArtikel OF ArtikelTyp AS SELECT TREATVALUEa AS ArtikelTyp WHERE VALUEa IS OF ONLY ArtikelTyp; CREATE VIEW Lebensmittel OF LebensmittelTyp AS SELECT TREATVALUEa AS LebensmittelTyp WHERE VALUEa IS OF ONLY LebensmittelTyp; CREATE VIEW Haushaltswaren OF HaushaltswarenTyp AS SELECT TREATVALUEa AS HaushaltswarenTyp WHERE VALUEa IS OF ONLY HaushaltswarenTyp; ArtikelTyp 123-4567-98, DVD, 24.99, Goldeneye..., NULL; ArtikelTyp 123-4567-99, DVD, 24.99, Goldfinger..., NULL; ArtikelSetTyp 989-4567-98, DVD-Box, 559.99, Die Box enthält..., NULL, CASTMULTISETSELECT REFa WHERE Bezeichnung = DVD AND Beschreibung LIKE Gold% AS ArtikelKollektionsTyp; LebensmittelTyp 481-4427-15, Wein, 34.99, 3 Auf den Bergen von..., NULL, 700, Keine Ahnung ; HaushaltswarenTyp 343-1197-71, Mixer, 59.99, Super leicht..., NULL, CURRENT_DATE, Weiss ; SELECT Nummer, Bezeichnung, Preis, Beschreibung FROM Artikel; SELECT Nummer, Bezeichnung, Preis, Beschreibung FROM AllgemeineArtikel; SELECT Nummer, Bezeichnung, Preis, Beschreibung, Artikel, a.anzahlartikel FROM ArtikelSet a; SELECT Nummer, Bezeichnung, Preis, Beschreibung, Gewicht, Zusammensetzung FROM Lebensmittel; SELECT Nummer, Bezeichnung, Preis, Beschreibung, Garantie, Farbe FROM Haushaltswaren; Aufgabe 2: Entwurf einer Funktion in Oracle-PLSQL Schreiben Sie eine Funktion, die als Parameter einen Primärschlüssel und das monatliche Einkommen eines Kunden erhält, dessen Kreditlimit errechnet werden soll. Dieses Limit beträgt normalerweise das dreifache seines Gehalts, minimal aber 500 und maximal 5000 Franken. Der so ermittelte Wert soll zurückgegeben werden. Aufgabe 3: Entwurf einer Prozedur in Oracle-PLSQL Entwerfen Sie eine Prozedur, die wiederum den Primärschlüssel eines Kunden und eine neue Telefonnummer übergeben bekommt. Diese Telefonnummer soll nun zusätzlich zu den bisher vorhandenen gespeichert werden. Beispiellösung für Aufgabe 1 und 2: Bevor wir die Funktion bzw. Prozedur umsetzen, wollen wir die zugrunde liegende Tabellen erzeugen, damit wir die Routinen später auch testen können. In Übung 8 hatten wir bereits einen Teil des Anwendungsszenarios aus Übung 1 umgesetzt. Darauf aufbauend implementieren wir zunächst die restlichen Klassen und danach die geforderten Routinen. 4
CREATE TYPE TelefonTabellenTyp AS TABLE OF VARCHAR20; CREATE TYPE AdresseTyp AS OBJECT Strasse VARCHAR30, Nr DECIMAL4, PLZ DECIMAL5, Ort VARCHAR40, Land VARCHAR25 NOT FINAL; CREATE TYPE PositionTyp AS OBJECT Artikel REF ArtikelTyp, Anzahl INTEGER ; CREATE TYPE PositionTabellenTyp AS TABLE OF PositionTyp; CREATE TYPE BestellungsTyp AS OBJECT Bestellnummer INTEGER, Eingangsdatum DATE, Status VARCHAR15, Positionen PositionTabellenTyp ; CREATE TYPE BestellungsTabellenTyp AS TABLE OF REF BestellungsTyp; CREATE TYPE PersonTyp AS OBJECT Name VARCHAR30, Anschrift AdresseTyp, Telefone TelefonTabellenTyp, Email VARCHAR25 NOT FINAL NOT INSTANTIABLE; CREATE TYPE KundeTyp UNDER PersonTyp Kundennummer INTEGER, Bestellungen BestellungsTabellenTyp, Kreditlimit DECIMAL12,2 FINAL; CREATE TYPE AngestellterTyp UNDER PersonTyp Personalnummer INTEGER, Gehalt DECIMAL12,2 FINAL; CREATE TABLE Bestellung OF BestellungsTyp PRIMARY KEYBestellnummer, 5 CHECKStatus IN InBearbeitung, Eingegangen, Geliefert, Bezahlt NESTED TABLE Positionen STORE AS Positionen; CREATE TABLE Kunde OF KundeTyp PRIMARY KEYKundennummer, Name NOT NULL, Anschrift NOT NULL, CHECKAnschrift.PLZ IS NOT NULL, CHECKKreditlimit <= 5000 NESTED TABLE Bestellungen STORE AS Kundenbestellungen NESTED TABLE Telefone STORE AS Kundentelefone; CREATE TABLE Angestellte OF AngestellterTyp PRIMARY KEYPersonalnummer, Name NOT NULL, Anschrift NOT NULL, CHECKAnschrift.PLZ IS NOT NULL, CHECKGehalt >= 2000 NESTED TABLE Telefone STORE AS Angestelltentelefone; -- Funktion Kundenkredit berechnet das Kreditlimit -- basierend auf dem Gehalt eines Kunden CREATE FUNCTION Kundenkreditgehalt DECIMAL RETURN DECIMAL AS limit DECIMAL; limit := 3 * gehalt; IF limit < 500.0 THEN limit:= 500; ELSE IF limit > 5000.0 THEN limit:= 5000; END IF; END IF; RETURN limit; -- PROCEDURE NeueNummer fügt eine neue -- Telefonnummer in die tabellenwertige Spalte -- Telefone eines bestimmten Kunden ein CREATE PROCEDURE NeueNummerknr INTEGER, nn VARCHAR AS INSERT INTO TABLESELECT Telefone FROM Kunde WHERE Kundennummer = knr VALUESnn; 6
-- Basierend auf den Artikel-Daten aus Uebung 8 -- erzeugen wir nun Daten für Bestellungen und -- Kunden, um die neue Routinen zu testen INSERT INTO Bestellung VALUES 7989, CURRENT_DATE, Eingegangen, PositionTabellenTyp PositionTypSELECT REFa WHERE Nummer = 123-4567-98, 1; INSERT INTO Bestellung VALUES 6134, CURRENT_DATE, InBearbeitung, PositionTabellenTyp PositionTypSELECT REFa WHERE Nummer = 989-4567-98, 1, PositionTypSELECT REFa WHERE Nummer = 481-4427-15, 12; -- Funktion Kundenkredit wird beim Erzeugen -- eines Kunden verwendet INSERT INTO Kunde VALUES James, AdresseTyp Haldeneggsteig, 4, 8092, Zürich, CH, TelefonTabellenTyp 0041-1-9876543, 0049-611-6733219, james@bond.uk, 1704, CASTMULTISETSELECT REFb FROM Bestellung b WHERE Bestellnummer = 7989 AS BestellungsTabellenTyp, Kundenkredit1000.0; INSERT INTO Kunde VALUES John, AdresseTyp Seestrasse, 13, 8008, Zürich, CH, 7 TelefonTabellenTyp 0041-1-2612345, john@wayne.usa, 6970, NULL, Kundenkredit3000.0; -- Aufruf der Prozedur NeueNummer CALL NeueNummer1704, 0041-1-45678912 ; -- Es ist auch möglich, die folgende Funktion zu -- definieren CREATE FUNCTION Kundenlimitknr INTEGER, gehalt DECIMAL RETURN DECIMAL AS limit DECIMAL; limit := 3 * gehalt; IF limit < 500.0 THEN limit:= 500; ELSE IF limit > 5000.0 THEN limit:= 5000; END IF; END IF; UPDATE Kunde SET Kreditlimit = limit WHERE Kundennummer = knr; RETURN limit; -- Ein Aufruf dieser Funktion ist innerhalb einer -- Anfrage nicht erlaubt SELECT KundenlimitKundennummer, 1500 FROM Kunde WHERE Kundennummer = 6970; -- Oracle gibt die folgende Fehlermeldung aus: -- FEHLER in Zeile 1: -- ORA-14551: DML-Vorgang kann innerhalb einer -- Abfrage nicht ausgeführt werden -- ORA-06512: in "SYSTEM.KUNDENLIMIT", Zeile 10 8
-- Ebenso ist ein Aufruf ein solchen Funktion -- nicht in einer DML-Anweisung gestattet UPDATE Kunde SET Kreditlimit = KundenlimitKundennummer, 1500 WHERE Kundennummer = 6970; -- Oracle gibt die folgende Fehlermeldung aus: -- FEHLER in Zeile 2: -- ORA-04091: Tabelle SYSTEM.KUNDE wird gerade -- geändert, TriggerFunktion sieht -- dies möglicherweise nicht -- ORA-06512: in "SYSTEM.KUNDENLIMIT", Zeile 10 -- Folgender Aufruf in einem PLSQL-Block ist -- dagegen möglich DECLARE test DECIMAL; Begin test := Kundenlimit6970, 1500; 9
Eidgenössische Technische Hochschule Zürich Swiss Federal Institute of Technology Zurich Institut für Informationssysteme Dr.C.Türker Objektrelationale, erweiterbare Datenbanken WS 0405 Übung 8 Extra Aufgabe 1: Rekursion Beispiellösung Gegeben sei folgende Definition einer Tabelle, die Verwandtschaftsbeziehungen verwaltet: CREATE TABLE Stammbaum MenschID INTEGER PRIMARY KEY, Name VARCHAR30 NOT NULL, GebDatum DATE, Mutter INTEGER REFERENCES Stammbaum, Vater INTEGER REFERENCES Stammbaum ; 1. Ermitteln Sie mittels SQL:2003 alle Vorfahren von Jim. WITH RECURSIVE VorfahrenMenschID, Vorfahr AS SELECT MenschID, Mutter SELECT MenschID, Vater SELECT v.menschid, s.mutter SELECT v.menschid, s.vater FROM Vorfahren WHERE Vorfahr IS NOT NULL ORDER BY MenschID; 2. Ermitteln Sie mittels SQL:2003 alle Nachkommen von Bob. 1 WITH RECURSIVE NachkommenMenschID, Nachkomme AS SELECT Mutter, MenschID SELECT Vater, MenschID WHERE v.nachkomme = s.mutter WHERE v.nachkomme = s.vater FROM Nachkommen WHERE MenschID IN SELECT MenschID WHERE Name = Bob ORDER BY MenschID; 3. Setzen Sie die obige Tabelle und die rekursiven Anfragen in DB2 um. DROP TABLE Stammbaum $ CREATE TABLE Stammbaum MenschID INTEGER NOT NULL PRIMARY KEY, Name VARCHAR30 NOT NULL, GebDatum DATE, Mutter INTEGER REFERENCES Stammbaum, Vater INTEGER REFERENCES Stammbaum $ INSERT INTO Stammbaum VALUES 1, Bob, 11-29-1927, NULL, NULL $ INSERT INTO Stammbaum VALUES 2, Joe, 10-23-1952, NULL, 1 $ INSERT INTO Stammbaum VALUES 7, Mark, 08-30-1957, NULL, NULL $ INSERT INTO Stammbaum VALUES 3, Joanna, 09-12-1954, NULL, NULL $ INSERT INTO Stammbaum VALUES 4, Kim, 03-15-1997, 3, 2 $ INSERT INTO Stammbaum VALUES 5, Jim, 12-24-1995, 3, 2 $ INSERT INTO Stammbaum VALUES 6, Cloe, 05-07-1999, 3, 7 $ WITH VorfahrenMenschID, Vorfahr AS SELECT MenschID, Mutter ALL SELECT MenschID, Vater 2
ALL SELECT v.menschid, s.mutter ALL SELECT v.menschid, s.vater FROM Vorfahren WHERE Vorfahr IS NOT NULL ORDER BY MenschID $ WITH NachkommenMenschID, Nachkomme AS SELECT Mutter, MenschID ALL SELECT Vater, MenschID ALL WHERE v.nachkomme = s.mutter ALL WHERE v.nachkomme = s.vater FROM Nachkommen WHERE MenschID IN SELECT MenschID WHERE Name = Bob ORDER BY MenschID $ 3
Eidgenössische Technische Hochschule Zürich Swiss Federal Institute of Technology Zurich Institut für Informationssysteme Dr.C.Türker Objektrelationale, erweiterbare Datenbanken WS 0405 Übung 8 Extra Aufgabe 1: Rekursion Beispiellösung Gegeben sei folgende Definition einer Tabelle, die Verwandtschaftsbeziehungen verwaltet: CREATE TABLE Stammbaum MenschID INTEGER PRIMARY KEY, Name VARCHAR30 NOT NULL, GebDatum DATE, Mutter INTEGER REFERENCES Stammbaum, Vater INTEGER REFERENCES Stammbaum ; 1. Ermitteln Sie mittels SQL:2003 alle Vorfahren von Jim. WITH RECURSIVE VorfahrenMenschID, Vorfahr AS SELECT MenschID, Mutter SELECT MenschID, Vater SELECT v.menschid, s.mutter SELECT v.menschid, s.vater FROM Vorfahren WHERE Vorfahr IS NOT NULL ORDER BY MenschID; 2. Ermitteln Sie mittels SQL:2003 alle Nachkommen von Bob. 1 WITH RECURSIVE NachkommenMenschID, Nachkomme AS SELECT Mutter, MenschID SELECT Vater, MenschID WHERE v.nachkomme = s.mutter WHERE v.nachkomme = s.vater FROM Nachkommen WHERE MenschID IN SELECT MenschID WHERE Name = Bob ORDER BY MenschID; 3. Setzen Sie die obige Tabelle und die rekursiven Anfragen in DB2 um. DROP TABLE Stammbaum $ CREATE TABLE Stammbaum MenschID INTEGER NOT NULL PRIMARY KEY, Name VARCHAR30 NOT NULL, GebDatum DATE, Mutter INTEGER REFERENCES Stammbaum, Vater INTEGER REFERENCES Stammbaum $ INSERT INTO Stammbaum VALUES 1, Bob, 11-29-1927, NULL, NULL $ INSERT INTO Stammbaum VALUES 2, Joe, 10-23-1952, NULL, 1 $ INSERT INTO Stammbaum VALUES 7, Mark, 08-30-1957, NULL, NULL $ INSERT INTO Stammbaum VALUES 3, Joanna, 09-12-1954, NULL, NULL $ INSERT INTO Stammbaum VALUES 4, Kim, 03-15-1997, 3, 2 $ INSERT INTO Stammbaum VALUES 5, Jim, 12-24-1995, 3, 2 $ INSERT INTO Stammbaum VALUES 6, Cloe, 05-07-1999, 3, 7 $ WITH VorfahrenMenschID, Vorfahr AS SELECT MenschID, Mutter ALL SELECT MenschID, Vater 2
ALL SELECT v.menschid, s.mutter ALL SELECT v.menschid, s.vater FROM Vorfahren WHERE Vorfahr IS NOT NULL ORDER BY MenschID $ WITH NachkommenMenschID, Nachkomme AS SELECT Mutter, MenschID ALL SELECT Vater, MenschID ALL WHERE v.nachkomme = s.mutter ALL WHERE v.nachkomme = s.vater FROM Nachkommen WHERE MenschID IN SELECT MenschID WHERE Name = Bob ORDER BY MenschID $ 3