Informationssysteme IS-K WS 2001/2002 Praktische ¨Ubung 2

Werbung
¥¥¥¥¥¥
¥¥¥¥¥¥
Institut für Informationssysteme
¥¥¥¥¥¥ ¥¥¥¥¥¥ ¥¥¥¥¥¥
¥¥¥¥¥¥ ¥¥¥¥¥¥ ¥¥¥¥¥¥
Prof. Dr. H.-J. Schek
F. Akal, K. Jauslin, K. Haller
M. Mlivoncic, M. Schmidt, C. Schuler
Eidgenössische Technische Hochschule Zürich
Swiss Federal Institute of Technology Zurich
Informationssysteme IS-K WS 2001/2002
Praktische Übung 2
Beispiellösung
Aufgabe 1: VIEWs in Oracle–SQL
Wir wollen zunächst sämtliche Informationen zusammenstellen, die wir über einen bestimmten
Geschäftsreisenden zur Verfügung haben, d.h. neben seinem Beruf auch seine Adresse und seine
Geschäftsadresse.
a) Geben Sie ein bzw. mehrere SQL-Statements an, die sämtliche vorhandenen Daten über “Fred
Feuerstein” liefern.
SELECT p.*, gr.Beruf, g.Name Gesch_Name, g.Strasse Gesch_Strasse,
g.Stadt Gesch_Stadt, g.PLZ Gesch_PLZ
FROM Person p, Geschaeftsreisender gr, Geschaeft g
WHERE p.Name = gr.Name AND gr.GName = g.Name AND
p.Name = ’Fred Feuerstein’;
b) Wir betrachten nun die folgende SQL–VIEW:
CREATE OR REPLACE VIEW Geschaeftsreisender_VW AS
SELECT p.*, gr.Beruf, g.Name Gesch_Name, g.Strasse Gesch_Strasse,
g.Stadt Gesch_Stadt, g.PLZ Gesch_PLZ
FROM Person p, Geschaeftsreisender gr, Geschaeft g
WHERE p.Name = gr.Name AND gr.GName = g.Name;
Führen Sie den Befehl in Ihrer Datenbank aus, um die View zu erzeugen. Wie lässt sich die
Anfrage aus der vorherigen Teilaufgabe nun kürzer Formulieren?
SELECT * FROM Geschaeftsreisender_vw WHERE Name=’Fred Feuerstein’;
c) Definieren Sie eine View, Reise Statistik, die für jede Firma (Name) die Anzahl der Dienstreisen (Reisen Total ) auflistet. Testen Sie Ihre View anschliessend mit einem entsprechendem
SELECT –Befehl.
Hinweis: Verwenden Sie GROUP BY.
CREATE OR REPLACE VIEW Reise_Statistik AS
SELECT g.Name, COUNT(r.Name) Reisen_Total
FROM Reise r, Geschaeftsreisender gr, Geschaeft g
WHERE r.Name = gr.Name AND gr.GName = g.Name
GROUP BY g.Name ;
d) Definieren Sie eine weitere View, ReiseNachZuerich Statistik, die für jede Firma (Name) die Anzahl der Dienstreisen nach Zürich (Reisen Zuerich) auflistet. Testen Sie Ihre View anschliessend
mit einem entsprechendem SELECT –Befehl.
CREATE OR REPLACE VIEW ReiseNachZuerich_Statistik AS
SELECT g.Name, COUNT(r.Name) Reisen_Zuerich
FROM Reise r, Geschaeftsreisender gr, Geschaeft g
WHERE r.Name = gr.Name AND gr.GName = g.Name AND
r.Destination = ’Zuerich’
GROUP BY g.Name ;
Aufgabe 2: TRIGGER in Oracle–SQL
1
a) Versuchen Sie einen Mitarbeiter über die View einzufügen:
INSERT INTO Geschaeftsreisender_vw
VALUES (’Hermann Meier’, ’Seestr. 10’, ’Küsnacht’, 8700 , ’Aussendienst-Support’,
’Easy-Informatik’, ’Computerweg 1’, ’Zürich’, 8040);
Was bedeutet die Fehlermeldung, die Sie erhalten?
ORA-01776: cannot modify more than one base table through a join view
Diese Fehlermeldung besagt, dass Oracle zwar in der Lage ist, Änderungen an einer Basis–
Tabelle, die der View zugrunde liegt, vorzunehmen, aber nich an mehreren gleichzeitig.
b) Definieren Sie nun den folgenden Trigger in Ihrer Datenbank. Versuchen Sie danach, den Mitarbeiter nochmals über die View einzufügen.
CREATE OR REPLACE TRIGGER Geschaeftsreisender_vw_trigger
INSTEAD OF INSERT ON Geschaeftsreisender_vw FOR EACH ROW
DECLARE
rowcount INTEGER;
BEGIN
SELECT count(*) INTO rowcount FROM Geschaeft WHERE Name = :new.Gesch_Name;
IF (rowcount = 0) THEN
INSERT INTO Geschaeft
VALUES (:new.Gesch_Name, :new.Gesch_Strasse, :new.Gesch_Stadt, :new.Gesch_PLZ);
END IF;
INSERT INTO Person VALUES (:new.Name, :new.Strasse, :new.Stadt, :new.PLZ);
INSERT INTO Geschaeftsreisender VALUES (:new.Name, :new.Gesch_Name, :new.Beruf);
END;
/
Wurden die Daten nun korrekt in die entsprechenden Tabellen geschrieben?
Was passiert, wenn wir weitere Mitarbeiter der Firma “Easy-Informatik” über die View
einfügen? Ist dies sinnvoll?
Beispiel:
INSERT INTO Geschaeftsreisender_vw VALUES (’Ursi Meier’, ’Seestr.
10’, ’Küsnacht’, 8700 , ’Programmiererin’, ’Easy-Informatik’,
’Computergasse 41’, ’Baerlin’, 1234);
Dies ist nur in Fällen sinnvoll, sofern nicht noch gleichzeitig versucht wird, die Anschrift der
Firma zu ändern. Wenn dies gewünscht wird, könnte man den Trigger aber entprechend erweitern. Ein ELSE –Zweig bei der bedingten Anfrage könnte mittels UPDATE –Statement die
entsprechende Änderung vornehmen.
Allgemein wären weitere Trigger denkbar, die auch ein UPDATE der gesamten View vornehmen.
Beachten Sie die Reihenfolge der INSERT–Befehle in der Trigger-Definition. Was passiert, wenn
man die Reihenfolge der INSERT–Befehle des Triggers vertauscht bzw. den IF–Block ans Ende
der Definition stellt? Probieren Sie es ruhig einmal aus und versuchen Sie dann erneut Daten
über die View einzufügen.
Wegen den Fremdschlüsselbeziehungen müssen die INSERT –Befehle in exakt dieser Reihenfolge
vorgenommen werden.
Wir wollen versuchen, das Problem aus Teilaufgabe 1c) nun mit Hilfe von Triggern zu lösen. Hierzu
betrachten wir folgende Table–Definition:
CREATE TABLE Reise_Statistik_Table (
Name
VARCHAR2(20) NOT NULL,
Reisen_Total INTEGER,
PRIMARY KEY(Name),
FOREIGN KEY(Name) REFERENCES Geschaeft ON DELETE CASCADE
);
2
c) Geben Sie an, wie Sie diese Tabelle mit den korrekten Werten füllen würden.
Hinweis: Verwenden Sie z.B. den INSERT INTO–Befehl.
INSERT INTO Reise_Statistik_Table
SELECT Name, Reisen_Total FROM Reise_Statistik;
d) Schreiben Sie einen Trigger Statistik trigger1, der jeweils beim Einfügen einer neuen Dienstreise
in Reise die Statistik aktualisiert.
Hinweis: Sofern Sie es nicht bereits wissen, überlegen Sie sich, wie Sie mittels UPDATE–
Kommando einen Wert inkrementieren können.
CREATE OR REPLACE TRIGGER Statistik_trigger1 AFTER INSERT ON Reise
FOR EACH ROW
DECLARE
rowcount INTEGER;
BEGIN
SELECT count(*) INTO rowcount FROM Reise_Statistik_Table WHERE Name =
(SELECT GName FROM Geschaeftsreisender WHERE Name=:new.Name);
IF (rowcount = 0) THEN
INSERT INTO Reise_Statistik_Table
SELECT GName, 0 FROM Geschaeftsreisender WHERE Name=:new.Name ;
END IF;
UPDATE Reise_Statistik_Table SET Reisen_Total=Reisen_Total+1 WHERE Name =
(SELECT GName FROM Geschaeftsreisender WHERE Name=:new.Name);
END;
/
show errors;
e) Schreiben Sie einen Trigger Statistik trigger2, der jeweils beim Entfernen einer Dienstreise aus
der Tabelle Reise die Statistik aktualisiert.
CREATE OR REPLACE TRIGGER Statistik_trigger2 AFTER DELETE ON Reise
FOR EACH ROW
BEGIN
-- hier brauchen wir nichts ueberpruefen, da alles passen muesste:
-- fuer Destination existiert Reisender, dafuer wiederum Geschaeft.
-- beim Einfuegen von Reise wurde diese Row auf jeden Fall angelegt!
UPDATE Reise_Statistik_Table SET Reisen_Total=Reisen_Total-1 WHERE Name =
(SELECT GName FROM Geschaeftsreisender WHERE Name=:old.Name);
END;
/ show errors;
Aufgabe 3: Zusätzliche Überlegungen
Erläutern Sie die Stärken und Schwächen der vorgestellten Lösungen mittels Trigger bzw. Views.
Was passiert in der Datenbank wenn ein Mitarbeiter die Firma wechselt; was, wenn eine Firma in
Konkurs geht (d.h. aus der Tabelle gelöscht wird)?
Sind die Daten danach immer konsistent? Welche Seiteneffekte treten auf? Welche SQL–
Anweisungen unserer Definitionen sind dafür verantwortlich? Welche weitere Funktionalität wäre
wünschenswert?
3
Die sog. “referentielle Integrität” der Daten wird durch die Verwendung der ON–DELETE–
CASCADE –Anweisungen in der Datenbank garantiert. Dies bedeutet in unserem Fall, dass das
Löschen eines Geschäftes auch das automatische Löschen aller Geschäftsreisenden zur Folge hat.
Die Personen an sich bleiben in der Datenbank; die Dienstreisen hingegen werden gelöscht.
Im Modell ist nicht vorgesehen, dass es Personen gibt, die einen Beruf haben und nicht als Geschäftsreisende geführt werden. Ebenso wird beim Wegfall der Anstellung (d.h. der Eintrag in der Tabelle
Geschaeftsreisender wird gelöscht) die Information “Beruf” ebenfalls verloren gehen. Wenn dies
nicht gewünscht ist, muss es beim Design bereits berücksichtigt werden und das Beschäftigungsverhältnis von der Berufsangabe entkoppelt werden.
Eindeutige Personen- und Firmennamen sind ebenfalls in der Realität eher selten. Man könnte
hier natürlich auf Personen–IDs bzw. Firmen–IDs zurückgreifen, wie dies in der ersten praktischen
Übung gemacht wurde. Hier wurde darauf verzichtet, um die SQL–Definitionen übersichtlicher zu
halten.
4
Herunterladen