Musterlösung

Werbung
Eidgenössische
Technische Hochschule
Zürich
Ecole polytechnique fédérale de Zurich
Politecnico federale di Zurigo
Swiss Federal Institute of Technology Zurich
Dr. C. Türker
Objektrelationale, erweiterbare Datenbanken
WS03/04
Übung 9
Musterlösung
Aufgabe 1: Entwurf einer Funktion in Oracle-PL/SQL
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 2: Entwurf einer Prozedur in Oracle-PL/SQL
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.
CREATE TYPE TelefonTabellenTyp
AS TABLE OF VARCHAR(20);
/
CREATE TYPE AdresseTyp AS OBJECT (
Strasse VARCHAR(30),
Nr
DECIMAL(4),
PLZ
Ort
Land
DECIMAL(5),
VARCHAR(40),
VARCHAR(25)
)
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 VARCHAR(15),
Positionen PositionTabellenTyp
);
/
CREATE TYPE BestellungsTabellenTyp
AS TABLE OF REF BestellungsTyp;
/
CREATE TYPE PersonTyp AS OBJECT (
Name
VARCHAR(30),
Anschrift
AdresseTyp,
Telefone
TelefonTabellenTyp,
Email
VARCHAR(25)
)
NOT FINAL
NOT INSTANTIABLE;
/
CREATE TYPE KundeTyp UNDER PersonTyp (
Kundennummer INTEGER,
Bestellungen BestellungsTabellenTyp,
Kreditlimit DECIMAL(12,2)
)
FINAL;
/
CREATE TYPE AngestellterTyp UNDER PersonTyp (
Personalnummer INTEGER,
Gehalt
DECIMAL(12,2)
)
FINAL;
/
CREATE TABLE Bestellung OF BestellungsTyp (
PRIMARY KEY(Bestellnummer),
CHECK(Status IN (’InBearbeitung’, ’Eingegangen’,
’Geliefert’, ’Bezahlt’))
)
NESTED TABLE Positionen STORE AS Positionen;
CREATE TABLE Kunde OF KundeTyp (
PRIMARY KEY(Kundennummer),
Name
NOT NULL,
Anschrift
NOT NULL,
CHECK(Anschrift.PLZ IS NOT NULL),
CHECK(Kreditlimit <= 5000)
)
NESTED TABLE Bestellungen STORE AS Kundenbestellungen
NESTED TABLE Telefone STORE AS Kundentelefone;
CREATE TABLE Angestellte OF AngestellterTyp (
PRIMARY KEY(Personalnummer),
Name
NOT NULL,
Anschrift
NOT NULL,
CHECK(Anschrift.PLZ IS NOT NULL),
CHECK(Gehalt >= 2000)
)
NESTED TABLE Telefone STORE AS Angestelltentelefone;
---------------------------------------------------- Funktion Kundenkredit berechnet das Kreditlimit
-- basierend auf dem Gehalt eines Kunden
--------------------------------------------------CREATE FUNCTION Kundenkredit(gehalt DECIMAL)
RETURN DECIMAL
AS
limit DECIMAL;
BEGIN
limit := 3 * gehalt;
IF limit < 500.0 THEN limit:= 500;
ELSE IF limit > 5000.0 THEN limit:= 5000; END IF;
END IF;
RETURN limit;
END;
/
---------------------------------------------------- PROCEDURE NeueNummer fügt eine (neue)
-- Telefonnummer in die tabellenwertige Spalte
-- Telefone eines bestimmten Kunden ein
--------------------------------------------------CREATE PROCEDURE NeueNummer(knr INTEGER, nn VARCHAR)
AS
BEGIN
INSERT INTO TABLE(SELECT Telefone
FROM Kunde
WHERE Kundennummer = knr)
VALUES(nn);
END;
/
---------------------------------------------------- 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(
PositionTyp((SELECT REF(a)
FROM Artikel a
WHERE Nummer = ’123-4567-98’),
1)));
INSERT INTO Bestellung
VALUES (6134,
CURRENT_DATE,
’InBearbeitung’,
PositionTabellenTyp(
PositionTyp((SELECT REF(a)
FROM Artikel a
WHERE Nummer = ’989-4567-98’),
1),
PositionTyp((SELECT REF(a)
FROM Artikel a
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’),
’[email protected]’,
1704,
CAST(MULTISET(SELECT REF(b)
FROM Bestellung b
WHERE Bestellnummer = 7989)
AS BestellungsTabellenTyp),
Kundenkredit(1000.0));
INSERT INTO Kunde
VALUES(’John’,
AdresseTyp(’Seestrasse’, 13, 8008, ’Zürich’, ’CH’),
TelefonTabellenTyp(’0041-1-2612345’),
’[email protected]’,
6970,
NULL,
Kundenkredit(3000.0));
---------------------------------------------------- Aufruf der Prozedur NeueNummer
--------------------------------------------------CALL NeueNummer(1704, ’0041-1-45678912’);
---------------------------------------------------- Es ist auch möglich, die folgende Funktion zu
-- definieren
--------------------------------------------------CREATE FUNCTION Kundenlimit(knr INTEGER,
gehalt DECIMAL)
RETURN DECIMAL
AS
limit DECIMAL;
BEGIN
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;
END;
/
---------------------------------------------------- Ein Aufruf dieser Funktion ist innerhalb einer
-- Anfrage nicht erlaubt
--------------------------------------------------SELECT Kundenlimit(Kundennummer, 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
---------------------------------------------------- Ebenso ist ein Aufruf ein solchen Funktion
-- nicht in einer DML-Anweisung gestattet
--------------------------------------------------UPDATE Kunde
SET Kreditlimit = Kundenlimit(Kundennummer, 1500)
WHERE Kundennummer = 6970;
---------------------------------------------------- Oracle gibt die folgende Fehlermeldung aus:
---------------------------------------------------- FEHLER in Zeile 2:
-- ORA-04091: Tabelle SYSTEM.KUNDE wird gerade
-geändert, Trigger/Funktion sieht
-dies möglicherweise nicht
-- ORA-06512: in "SYSTEM.KUNDENLIMIT", Zeile 10
---------------------------------------------------- Folgender Aufruf in einem PL/SQL-Block ist
-- dagegen möglich
--------------------------------------------------DECLARE
test DECIMAL;
Begin
test := Kundenlimit(6970, 1500);
END;
/
Herunterladen