Prüfung Datenbanksysteme, 17. Juli 2003 S. 1 Lösungen Klausur Datenbanksysteme Aufgaben (Punkte ohne Gewähr) Für eine Spedition/Logistikunternehmen soll eine Datenbank erstellt werden. Sie sehen auf dem letzten Blatt dazu Abbildung 2: Ausschnitt aus einem Entity-Relationship-Diagramm der SpeditionsDatenbank. Erklärung des Ausschnitts: Firmen sind die Kunden der Spedition. Privatkunden werden nicht bedient. Die Adressen einer Firma werden nicht direkt gespeichert, sondern als Relation Firmenadresse zum Entity-Set Ort. Die Firmen vergeben Transport-Aufträge an die Spedition. Die Relationen von bzw. nach geben dabei die Absender- bzw. Emfängeradresse an. Die Waren sollen am Starttermin abgeholt werden und am Endtermin geliefert werden. Status kann die Werte: 'Auftrag erteilt', 'Transport geplant', 'Transport begonnen', 'Transport erfolgreich abgeschlossen', 'Transport fehlerhaft abgeschlossen', 'Rechnung gestellt', 'Rechnung bezahlt' bekommen. Jeder Auftrag umfasst ein oder mehrere Auftragspositionen, das sind die Waren, die tranportiert werden sollen. Da die gleichen Waren immer wieder transportiert werden müssen, z. B. immer wieder Kisten mit Äpfeln, werden die Daten der Waren extra in der Entity Warenart gespeichert. Z. B. könnte eine Auftragsposition die Ware mit der ID 500 sein, Menge ist 200 Stück. Dabei handelt es sich um die Warenart 10, das sind 'Kisten mit Äpfeln', Untertyp ist 'Jona Gold' und das Gewicht einer Kiste beträgt 22 kg. Aufgabe 1: Ergänzung des Entity-Relationship-Diagramms (35) Das ER-Diagramm ist noch nicht vollständig. Ergänzen Sie das ER-Diagramm in Abbildung 2 um weitere Entities und Relationen. Achten sie darauf, ... • dass Sie ein ER-Diagramm erstellen sollen und nicht ein Diagramm einer relationalen Tabellenstruktur, d.h. M:N-Relationen sind noch nicht in Verbindungstabellen umgewandelt, es gibt mehrwertige Attribute, und eine Strukturierung in Unterentities ist möglich. • dass Sie Anomalien und Redundanzen vermeiden. • dass Sie die Art der Relationen in der ausführlichen (min, max)-Schreibweise kennzeichnen. Unten stehende Informationen sollen in der Datenbank enthalten sein und effizient abgefragt werden können. Informationen, die hier nicht genannt sind, brauchen auch nicht ins ER-Diagramm, selbst wenn Sie sie für eine Speditions-Datenbank für sinnvoll erachten. • • Die Spedition transportiert nur Container. Alle Waren werden in Container verladen. Waren, die nicht in Container verladen werden können, wie z. B. Erdöl, werden von unserer Spedition nicht transportiert. Jeder Container hat eine Seriennummer, eine Normgröße (möglich sind die Werte 'einfach' und 'doppelt') und einen Typ (Typen sind z. B. 'normal' oder 'Kühlcontainer'). Folgende Abfragen sollen möglich sein: - Suche nach allen Waren, die in einem bestimmten Container verpackt sind. - Suche nach allen Containern, in die eine bestimmte Ware verpackt ist. Dies können auch mehrere Container sein, wenn die Ware nicht in einen hinein passt. Die Spedition hat zwei verschiedene Transportmittel: LKW und Schiffe. Für jeden LKW soll aus der Datenbank erfragt werden können: das Kennzeichen, das Eigengewicht, das zulässige Gesamtgewicht , die Maße (Länge, Breite und Höhe), die Motorleistung, das Datum der Erstzulassung, die Ladekapazität an Containern der Normgröße 'einfach' und außerdem die zulässige Höchstgeschwindigkeit und die Zahl der Achsen. Für jedes Schiff soll aus der Datenbank erfragt werden können: das Kennzeichen, das Eigenge- Prüfung Datenbanksysteme, 17. Juli 2003 S. 2 wicht, das zulässige Gesamtgewicht , die Maße (Länge, Breite und Höhe), die Motorleistung, das Datum der Erstzulassung, die Ladekapazität an Containern der Normgröße 'einfach' und außerdem der Tiefgang und der Typ (möglich sind die Werte 'Selbstfahrer' mit eigenem Motor und 'Schleppkahn'). • Die Spedition plant die Transporte, um die Aufträge abwickeln zu können. Nach der Zuordnung der Waren zu Containern (siehe oben) werden die Transporte durch eine Kette von Transportabschnitten realisiert. Folgende Abfragen sollen möglich sein: - Suche nach dem Startort eines Transportabschnitts. Dies ist ein Ort aus der Entity Ort. - Suche nach dem Zielort eines Transportabschnitts. - Suche nach dem Transportmittel für den Transportabschnitt. - Suche nach allen Containern, die mit dem Transportabschnitt transportiert werden. - Abfrage von Status, Beginn, Dauer und Verspätung eines Transportabschnitts. • Mittels eines GPS-Systems werden für alle Transportmittel alle Minuten die augenblicklichen Koordinaten zusammen mit der Zeit erfasst und abgespeichert. Tragen Sie eine Weak-Entity Fahrtdaten ein, die diese Werte speichert. • Warum ist Fahrtdaten eine Weak-Entity? (Bitte ankreuzen) Weil die Daten automatisch vom GPS-System ohne menschliches Zutun gespeichert werden. Weil Fahrtdaten nur zu einem anderen Entity-Set in Relation stehen und nicht zu mehreren. Eine Weak-Entity kombiniert Zeit- mit Ortsdaten. Genau das ist hier der Fall. ⌧ Weil ein Fahrtdaten-Datensatz nur mit dem zugehörigen Transportmittel eine sinnvolle Information darstellt, allein macht er keinen Sinn. Weil die Tabelle unweigerlich überläuft, wenn niemand die alten Fahrtdaten löscht. • Nicht alle Container sind für alle Warenarten geeignet. Folgende Abfragen sollen möglich sein: - Suche nach allen Containern, die für eine bestimmte Warenart geeignet sind. - Suche nach allen Warenarten, die in einen bestimmten Container verladen werden können. - Suche nach der Kapazität eines bestimmten Containers für eine bestimmte Warenart. Aufgabe 2: Ergänzung der Tabellenstruktur der Gremien-Datenbank (10) In Aufgabe 1: haben Sie unter anderem Zusatzinformation bezüglich Container und Transportabschnitten in das Entity-Relationship-Diagramm eingefügt. Wandeln Sie nur die zu Container und Transportabschnitte eingetragenen Entitie-Sets und Relationen in Tabellen eines relationalen Datenbanksystems um und tragen diese Tabellen in Abbildung 1: Tabellenstruktur der SpeditionsDatenbank ein. Die anderen Entity-Sets wie z. B. Transportmittel brauchen Sie nicht umwandeln und eintragen. Kennzeichnen Sie Primär- und Fremdschlüssel analog zu den bereits eingetragenen Tabellen. Hinweis: Die Aufgaben 3 bis 10 können allein durch die Information in Abbildung 1 und Abbildung 2 gelöst werden, Ihre Zusätze aus Aufgabe 1: und Aufgabe 2: sind dazu nicht notwendig. Aufgabe 3: SQL-Abfrage Geben Sie eine SQL-Abfrage an, die den Start- und Endtermin von jedem Auftrag ermittelt, dessen Status 'Auftrag erteilt' ist. SELECT Starttermin, Endtermin • FROM Auftrag • WHERE Status = 'Auftrag erteilt'; • (3) Prüfung Datenbanksysteme, 17. Juli 2003, Name: «Name» Matr.-Nr.: «MatrikelNr» Aufgabe 4: SQL-Abfrage S. 3 (10) Geben Sie eine SQL-Abfrage an, die die Bezeichnungen, Untertypen und Mengen aller Waren ermittelt, die die Firma mit Namen 'Marvelli GmbH' in Auftrag gegeben haben und die zu einem Auftrag gehören, dessen Status 'Transport begonnen' ist. SELECT Warenart.Bezeichnung, Warenart.Untertyp, Ware.Menge • FROM Firma •, Auftrag •, Ware •, Warenart • WHERE Firma.Name = 'Marvelli GmbH' • AND Status = 'Transport begonnen' • AND Auftrag.Auftraggeber_ID = Firma.ID • AND Ware.Auftrag_ID = Auftrag.ID • AND Ware.Warenart_ID = Warenart.ID •; Aufgabe 5: SQL-Abfrage (8) Geben Sie eine SQL-Abfrage an, die die IDs aller Aufträge ermittelt, die mehr als eine Auftragsposition (Ware) umfassen. SELECT ID • FROM Auftrag • WHERE (SELECT COUNT(Ware.ID) •• FROM Ware • WHERE Ware.Auftrag_ID = Auftrag.ID •)• > 1 •; Aufgabe 6: SQL-Abfrage (8) Geben Sie eine SQL-Abfrage an, die für jeden Auftrag (gekennzeichnet durch seine ID) das Gesamtgewicht der Waren ermittelt, die er umfasst. SELECT Ware.Auftrag_ID, • SUM(Warenart.Gewicht * Ware.Menge) •• Gesamtgewicht FROM Warenart •, Ware • WHERE Ware.Warenart_ID = Warenart.ID • GROUP By Ware.Auftrags_ID ••; Aufgabe 7: SQL-Anweisungen (16) Die Firma 'Marvelli GmbH' (sie hat die Firmen-ID 122) gibt am '18.7.2003, 10:00' einen neuen Transportauftrag. Er bekommt die ID 1428, soll vom Ort mit der ID 100 zum Ort mit der ID 200 gehen, am '22.7.2003, 6:00' beginnen und am '22.7.2003, 15:00' am Ziel sein. Der Auftrag umfasst 1000 Kisten Äpfel der Sorte 'Jona Gold' (Warenart-ID 10) und 5000 Kanister Apfelsaft 'Goldene Sonne' (WarenartID 50). Für den Transport wird ein Rechnungsbetrag von 370 Euro vereinbart. In der Tabelle Waren wird durch einen Trigger und eine Sequence bei Insert automatisch eine neue ID erzeugt; die ID braucht also von Ihnen nicht angegeben zu werden. Geben Sie SQL-Anweisungen an, mit denen diese Informationen (nur die in dieser Aufgabe genannten Informationen) in die Datenbank eingetragen werden. Beachten Sie dabei, dass die Warenarten, die Orte und die Firma bereits in der Datenbank vorhanden sind. INSERT • INTO Auftrag • VALUES • (1428 •, '18.7.2003, 10:00' •, '22.7.2003, 6:00', '22.7.2003, 15:00' , 'Auftrag erteilt' •, 370 •, 122 •, 100, 200 •); INSERT INTO Waren• (Menge, Auftrags_ID, Warenart_ID)• VALUES (1000 •, 1428 •, 10 •); INSERT INTO Waren • (Menge, Auftrags_ID, Warenart_ID) VALUES (5000, 1428, 50 •); Prüfung Datenbanksysteme, 17. Juli 2003 Aufgabe 8: Transaktionen S. 4 (6) In Aufgabe 7: wurde ein neuer Auftrag in die Datenbank geschrieben. Dabei werden mehrere SQLAnweisungen für verschiedene Tabellen ausgeführt. Beschreiben Sie, was bei einem Datenbankmangementsystem mit Transaktionssteuerung und einem Datenbankmanagementsystem ohne Transaktionen passiert, wenn nach der ersten SQL-Anweisung die Verbindung zum Client abreißt und die weiteren SQL-Anweisungen nicht mehr durchgeführt werden können. Ohne Transaktionssteuerung: Ohne Transaktionssteuerung werden die einzelnen Insert-Anweisungen unabhängig voneinander verarbeitet. Die erste Insert-Anweisung wird also ausgeführt die anderen nicht mehr. Damit ist in der Datenbank ein Auftrag ohne Waren, d. h. falsch (inkonsistent) gespeichert. Mit Transaktionssteuerung: Mit Transaktionssteuerung werden die 3 Insert-Anweisungen zu einer Transaktion zusammengefasst. Da nach der 1. Insert-Anweisung die beiden anderen nicht mehr kommen und insbesondere kein Commit gegeben wird, werden alle Teilaktionen mit Rollback wieder rückgängig gemacht. Es wird kein unvollständiger Auftrag in die Datenbank eingefügt, die Daten bleiben konsistent. Aufgabe 9: Embedded SQL (18) Die Spedition will eine Statistik über den Anteil kurzfristiger Aufträge aufstellen. Dazu wird für jede Kundenfirma der Anteil der Aufträge ermittelt, bei denen das Auftragsdatum nur 2 Tage oder weniger vor dem Starttermin liegt. Unten sehen Sie eine C-Funktion mit Embedded SQL, die diese Aufgabe ausführt. Analysieren Sie das Programm und versehen Sie es mit den richtigen Kommentaren an den richtigen Stellen. Dazu ist eine Liste mit möglichen Kommentaren angegeben. Tragen Sie die passenden Kommentarnummern in die gekennzeichneten Felder [ ] ein. void anteil_kurzfrist (void) {EXEC SQL BEGIN DECLARE SECTION; float Zeitdifferenz; char Firmenname [50]; int Firmenid; EXEC SQL END DECLARE SECTION; [4] [2] int kurzfrist_auftr, anzahl_auftr; /* Zählvariable */ float anteil_kurzfrist; /* Variable zur Berechnung des Ergebnis */ EXEC SQL WHENEVER SQLERROR GOTO sqlerror; EXEC SQL DECLARE firmen_cur CURSOR FOR SELECT ID, Name FROM Firma; EXEC SQL DECLARE auftrags_cur CURSOR FOR SELECT Starttermin – Auftragsdatum FROM Auftrag WHERE AuftraggeberID = :Firmenid; EXEC SQL OPEN firmen_cur; EXEC SQL FETCH firmen_cur INTO :Firmenid, :Firmenname; while (sqlca.sqlcode == 0) { anzahl_auftr = 0; kurzfrist_auftr = 0; EXEC SQL OPEN auftrags_cur; EXEC SQL FETCH auftrags_cur INTO :Zeitdifferenz; [5] [8] [10] [11] [16] [23] [26] [13] [19] Prüfung Datenbanksysteme, 17. Juli 2003, Name: «Name» Matr.-Nr.: «MatrikelNr» while (sqlca.sqlcode == 0) { anzahl_auftr = anzahl_auftr + 1; if (Zeitdifferenz <= 2) kurzfrist_auftr = kurzfrist_auftr + 1; EXEC SQL FETCH auftrags_cur INTO :Zeitdifferenz; } S. 5 [25] [27] [22] if (anzahl_auftr == 0) [28] printf("Firma %i, %s hat keine Aufträge erteilt", Firmenid, Firmenname); else {anteil_kurzfrist = 100 * kurzfrist_auftr / anzahl_auftr; printf ("Firma %i, %s hat %f Prozent kurzfristige Aufträge.\n", Firmenid, Firmenname, anteil_kurzfrist); } [31] EXEC SQL CLOSE auftrags_cur; EXEC SQL FETCH firmen_cur INTO :Firmenid, :Firmenname; } EXEC SQL CLOSE firmen_cur; return; [18] [32] sqlerror: printf("\n\n FEHLER: %s \n\n",sqlca.sqlerrm.sqlerrmc); EXEC SQL WHENEVER SQLERROR CONTINUE; return; } Kommentarliste: Nummer 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 Kommentar User-Work-Area zur Aufnahme eines Datensatzes des Cursors für die Waren User-Work-Area zur Aufnahme eines Datensatzes des Cursors für die Firmen User-Work-Area zur Aufnahme der gesamten Tabelle "Auftrag" User-Work-Area zur Aufnahme eines Datensatzes des Cursors für die Aufträge Wenn der Server bei einem beliebigen SQL-Kommando einen Laufzeitfehler meldet, springe zur angegebenen Marke für die Fehlerbehandlung. Deklariere einen Cursor, der alle Waren liefert Deklariere einen Cursor, der alle Waren für den gerade betrachteten Auftrag liefert Deklariere einen Cursor, der alle Firmen liefert Deklariere einen Cursor, der alle Aufträge liefert Deklariere einen Cursor, der alle Aufträge für die gerade betrachtete Firma liefert Führe die Abfrage nach allen Firmen durch Führe die Abfrage nach allen Aufträgen durch Führe die Abfrage nach allen Aufträgen für die gerade betrachtete Firma durch Führe die Abfrage nach der Firma für den gerade betrachteten Auftrag durch Führe die Abfrage nach allen Waren für den gerade betrachteten Auftrag durch Hole den ersten Firmendatensatz in die User-Work-Area Hole alle Firmendatensätze in die User-Work-Area Hole den nächsten Firmendatensatz in die User-Work-Area Hole den ersten Datensatz des Cursors auftrags_cur in die User-Work-Area Hole alle Datensätze des Cursors auftrags_cur in die User-Work-Area Hole alle Auftrags-Datensätze für die gerade betrachtete Firma in die User-Work-Area Hole den nächsten Datensatz des Cursors auftrags_cur in die User-Work-Area In einer Schleife führe für alle Firmen durch: In einer Schleife führe für alle Aufträge in der Datenbank durch: Prüfung Datenbanksysteme, 17. Juli 2003 25 26 27 28 29 30 31 32 33 S. 6 In einer Schleife führe für alle Aufträge der gerade betrachteten Firma durch: Setze für die gerade betrachtete Firma die Zählvariablen zurück Wenn die Zeitspanne zwischen Auftragsdatum und Starttermin weniger als 2 Tage beträgt, so handelt es sich um einen kurzfristigen Auftrag Fallunterscheidung ist notwendig, um eine Division durch 0 zu vermeiden Fallunterscheidung ist sinnvoll, da für eine Firma ohne Aufträge der Anteil der kurzfristigen Aufträge irreführend wäre Schließe den Cursor auftrags_cur; dies soll man immer durchführen, wenn ein Cursor nicht mehr gebraucht wird Schließe den Cursor auftrags_cur; dies ist notwendig, da er für die nächste Firma wieder neu geöffnet werden muss. Schließe den Cursor firmen_cur; dies soll man immer durchführen, wenn ein Cursor nicht mehr gebraucht wird. Schließe den Cursor firmen_cur; dies ist notwendig, da er für die nächste Firma wieder neu geöffnet werden muss. Aufgabe 10: Trigger (8) Erstellen Sie einen Datenbank-Trigger, der beim Eintrag eines neuen Auftrags überprüft, ob der Starttermin vor dem Endtermin liegt. Falls dies nicht der Fall ist, soll der Auftrag nicht in die Datenbank eingetragen werden, sondern ein Fehler generiert werden. Hinweis: Datumsfelder können mit den Operatoren <, >, = usw. verglichen werden. CREATE OR REPLACE TRIGGER Terminkontrolle BEFORE • AFTER //nichtzutreffendes streichen OR UPDATE OF //nichtzutreffendes streichen INSERT • OR DELETE ON Auftrag • //Tabellenname ergänzen FOR EACH ROW • FOR EACH STATEMENT //nichtzutreffendes streichen BEGIN if :new•.Endtermin <• :new.Starttermin then raise_application_error• (-20010, 'Endtermin vor Starttermin'•); end if; END; / Prüfung Datenbanksysteme, 17. Juli 2003, Name: «Name» Firma Matr.-Nr.: «MatrikelNr» Firmenadresse Ort ID Firmen_ID ID Name Name2 Branche Ort_ID Strasse_HNr PLZ Ortsname Telefon geogr_Länge geogr_Breite Auftrag ID Auftragsdatum Starttermin Endtermin Status Rechnungsbetrag Auftraggeber_ID von_ID nach_ID Container SerienNr Ware verpackt ID Ware_ID Menge Container_ID Normgröße Typ Auftrag_ID Warenart_ID geeignet_für Transportabschnitt Warenart_ID Warenart ID Bezeichnung Untertyp Gewicht ID Container_ID Kapazität wird_transportiert _in Container_ID Transportabschnitt_ID Abbildung 1: Tabellenstruktur der Speditions-Datenbank Status Beginn Dauer Verspätung Transportmittel_ID Startort_ID Zielort_ID S. 7 Prüfung Datenbanksysteme, 17. Juli 2003 S. 8 Länge Kennzeichen Eigengewicht Motorleistung zul_Ges_Gew Erstzulassung Ladekapazität Maße Breite Höhe Tiefgang Transportmittel (0,N) Koordinaten mit ↑ (0,N) ← transportiert ID (1,N) (1,1) (1,1) Typ Normgröße ist_geeignet ↓ (1,N) Container ID ist_in ↑ nach → (1,1) (0,N) ID Strasse_HNr PLZ Ortsname Telefon (0,N) nach ↑ (1,1) Koordinaten (1,N) (1,1) Firmenadresse Status Ware Achszahl Ort von ↑ Dauer Kapazität Menge von → (0,N) (0,N) Beginn (0,N) ID zul_Vmax Transportabschnitt (0,N) (1,N) Typ LKW (0,N) (1,1) Fahrtdaten Schiff ⊃ hat ↓ Zeit ⊃ d Firma (1,N) Verspätung (1,1) (1,1) ← umfasst hat ↓ (1,N) (1,1) Auftrag (0,N) ← gibt Name (0,N) Name2 Warenart ID Bezeichnung Untertyp ID ID Auftragsdatum Gewicht Status Starttermin Rechnungsbetrag Branche Endtermin ID Strasse_HNr PLZ Ort Ortsname Telefon (0,N) (0,N) von ↑ nach ↑ (1,1) Koordinaten (1,N) (1,1) Firmenadresse ID Menge Ware Firma (1,N) (1,1) (1,1) ist_von ↓ ← umfasst (1,N) Auftrag (1,1) ← gibt (0,N) (0,N) Name2 Warenart ID Bezeichnung Untertyp ID Name ID Gewicht Auftragsdatum Status Starttermin Rechnungsbetrag Branche Endtermin Abbildung 2: Ausschnitt aus einem Entity-Relationship-Diagramm der Speditions-Datenbank Prüfung Datenbanksysteme, 17. Juli 2003 S. 9