\documentclass{bschlangaul-aufgabe} \bLadePakete{rmodell,syntax} \begin{document} \bAufgabenMetadaten{ Titel = {Aufgabe 7}, Thematik = {Formel-1-Rennen}, Referenz = 66116-2019-H.T2-TA2-A7, RelativerPfad = Examen/66116/2019/09/Thema-2/Teilaufgabe-2/Aufgabe-7.tex, ZitatSchluessel = examen:66116:2019:09, BearbeitungsStand = mit Lösung, Korrektheit = unbekannt, Ueberprueft = {unbekannt}, Stichwoerter = {SQL, SQL mit Übungsdatenbank, EXCEPT, Top-N-Query, ALTER TABLE, TRIGGER}, EinzelpruefungsNr = 66116, Jahr = 2019, Monat = 09, ThemaNr = 2, TeilaufgabeNr = 2, AufgabeNr = 7, } Gegeben sind folgende Relationen aus einem Verwaltungssystem für die jährlichen Formel-1-Rennen: \index{SQL} \footcite{examen:66116:2019:09} \begin{bRelationenModell} Strecke(\bPrimaer{Strecken\_ID}, Streckenname, Land, Länge) Fahrer(\bPrimaer{Fahrer\_ID}, Fahrername, Nation, Rennstall) Rennen(\bPrimaer{Strecken\_ID[Strecke], Jahr}, Wetter) Rennteilnahme(\bPrimaer{Fahrer\_ID[Fahrer], Strecken\_ID[Rennen], Jahr[Rennen]}, Rundenbestzeit, Gesamtzeit, disqualifiziert) FK (Strecken\_ID, Jahr) referenziert Rennen (Strecken\_ID, Jahr) \end{bRelationenModell} % Datenbankname: formel1 \begin{minted}{sql} CREATE TABLE Fahrer ( Fahrer_ID INTEGER PRIMARY KEY, Fahrername VARCHAR(100) NOT NULL, Nation VARCHAR(100) NOT NULL, Rennstall VARCHAR(100) NOT NULL ); CREATE TABLE Strecke ( Strecken_ID INTEGER PRIMARY KEY, Streckenname VARCHAR(100) NOT NULL, Land VARCHAR(100) NOT NULL, Länge NUMERIC(5,3) NOT NULL ); CREATE TABLE Rennen ( Strecken_ID INTEGER REFERENCES Strecke(Strecken_ID), Jahr INTEGER NOT NULL, Wetter VARCHAR(10) NOT NULL, PRIMARY KEY (Strecken_ID, Jahr) ); CREATE TABLE Rennteilnahme ( Fahrer_ID INTEGER REFERENCES Fahrer(Fahrer_ID), Strecken_ID INTEGER REFERENCES Strecke(Strecken_ID), Jahr INTEGER NOT NULL, Rundenbestzeit NUMERIC(5,3) NOT NULL, Gesamtzeit NUMERIC(5,3) NOT NULL, disqualifiziert BOOLEAN NOT NULL, PRIMARY KEY (Fahrer_ID, Strecken_ID, Jahr) ); INSERT INTO Fahrer VALUES (1, 'Kimi Räikkönen', 'Finnland', 'Alfa Romeo'), (2, 'Rubens Barrichello', 'Brasilien', 'Brawn'), (3, 'Fernando Alonso', 'Spanien', 'Ferrari'), (4, 'Michael Schumacher', 'Deutschland', 'Ferrari'), (5, 'Jenson Button', 'Vereinigtes Königreich Großbritannien', 'McLaren'), (6, 'Felipe Massa', 'Brasilien', 'Ferrari'), (7, 'Lewis Hamilton', 'Vereinigtes Königreich Großbritannien', 'Williams'), (8, 'Riccardo Patrese', 'Italien', 'Williams'), (9, 'Sebastian Vettel', 'Deutschland', 'Ferrari'), (10, 'Jarno Trulli', 'Italien', 'Toyota'); INSERT INTO Strecke VALUES (1, 'Autodromo Nazionale Monza', 'Italien', 5.793), (2, 'Circuit de Monaco', 'Monaco', 3.340), (3, 'Silverstone Circuit', 'Vereinigtes Königreich', 5.891), (4, 'Circuit de Spa-Francorchamps', 'Belgien', 7.004), (5, 'Circuit Gilles-Villeneuve', 'Kanada', 4.361), (6, 'Nürburgring', 'Deutschland', 5.148), (7, 'Hockenheimring', 'Deutschland', 4.574), (8, 'Interlagos', 'Brasilien', 4.309), (9, 'Hungaroring', 'Ungarn', 4.381), (10, 'Red Bull Ring', 'Österreich', 5.942), (11, 'Abu Dhabi', 'Abu Dhabi', 5.554); INSERT INTO Rennen VALUES (11, 2011, 'sonnig'), (10, 2006, 'sonnig'), (9, 2007, 'regnerisch'), (8, 2008, 'regnerisch'), (7, 2009, 'sonnig'), (6, 2010, 'regnerisch'), (5, 2011, 'sonnig'), (4, 2012, 'sonnig'), (3, 2013, 'sonnig'), (2, 2014, 'regnerisch'), (1, 2015, 'regnerisch'); INSERT INTO Rennteilnahme VALUES (1, 11, 2011, 2.001, 90.001, FALSE), (2, 11, 2011, 2.002, 90.002, FALSE), (3, 11, 2011, 2.003, 90.003, FALSE), (4, 11, 2011, 2.004, 89.999, FALSE), (5, 11, 2011, 2.005, 90.005, FALSE), (6, 11, 2011, 2.005, 99.009, FALSE), (4, 10, 2006, 2.782, 90.005, TRUE), (3, 10, 2006, 2.298, 90.005, TRUE), (3, 9, 2009, 2.253, 90.005, TRUE), (2, 10, 2006, 2.005, 90.005, TRUE), (2, 9, 2009, 3.298, 90.342, TRUE), (2, 8, 2008, 4.782, 78.005, TRUE); \end{minted} \index{SQL mit Übungsdatenbank} \noindent Der Einfachheit halber wird angenommen, dass Fahrer den Rennstall nicht wechseln können. Das Attribut „disqualifiziert“ kann die Ausprägungen „ja“ und „nein“ haben. Formulieren Sie folgende Abfragen in SQL. Vermeiden Sie nach Möglichkeit übermäßige Nutzung von Joins und Views. \begin{enumerate} \item Geben Sie für jeden Fahrer seine ID sowie die Anzahl seiner Disqualifikationen in den Jahren 2005 bis 2017 aus. Ordnen Sie die Ausgabe absteigend nach der Anzahl der Disqualifikationen. \begin{bAntwort} \begin{minted}{sql} SELECT Fahrer_ID, COUNT(disqualifiziert) as anzahl_disqualifikationen FROM Rennteilnahme WHERE disqualifiziert = TRUE GROUP BY Fahrer_ID, disqualifiziert ORDER BY anzahl_disqualifikationen DESC; \end{minted} \end{bAntwort} \item Gesucht sind alle Länder, aus denen noch nie ein Fahrer disqualifiziert wurde.\index{EXCEPT} \begin{bAntwort} \begin{minted}{sql} SELECT Nation FROM Fahrer GROUP BY Nation EXCEPT SELECT f.Nation FROM Fahrer f, Rennteilnahme t WHERE f.Fahrer_ID = t.Fahrer_ID AND t.disqualifiziert = TRUE GROUP BY f.Nation; \end{minted} \end{bAntwort} \item Gesucht sind die ersten fünf Plätze des Rennens von 2011 in „Abu Dhabi“ (Streckenname). Die Ausgabe soll nach der Platzierung absteigend erfolgen. Geben Sie Fahrer\_ID, Fahrername, Nation und Rennstall mit aus. \begin{bAntwort} Mit LIMIT \begin{minted}{sql} SELECT f.Fahrer_ID, f.Fahrername, f.Nation, f.Rennstall FROM Fahrer f, Rennteilnahme t, Strecke s WHERE f.Fahrer_ID = t.Fahrer_ID AND s.Strecken_ID = t.Strecken_ID AND s.Streckenname = 'Abu Dhabi' AND t.Jahr = 2011 ORDER BY t.Gesamtzeit ASC LIMIT 5; \end{minted} Als Top-N-Query\index{Top-N-Query}: \begin{minted}{sql} CREATE VIEW Rennen_Abu_Dhabi AS SELECT f.Fahrer_ID, f.Fahrername, f.Nation, f.Rennstall, t.Gesamtzeit FROM Fahrer f, Rennteilnahme t, Strecke s WHERE f.Fahrer_ID = t.Fahrer_ID AND s.Strecken_ID = t.Strecken_ID AND s.Streckenname = 'Abu Dhabi' AND t.Jahr = 2011 ORDER BY t.Gesamtzeit ASC; SELECT a.Fahrer_ID, a.Fahrername, a.Nation, a.Rennstall FROM Rennen_Abu_Dhabi a, Rennen_Abu_Dhabi b WHERE a.Gesamtzeit >= b.Gesamtzeit GROUP BY a.Fahrer_ID, a.Fahrername, a.Nation, a.Rennstall, a.Gesamtzeit HAVING COUNT(*) <= 5 ORDER BY a.Gesamtzeit; \end{minted} \end{bAntwort} \item Führen Sie eine neue Spalte \texttt{Gehalt} in die Tabelle \texttt{Fahrer} ein. Da sich die Prämien für die Fahrer nach einem Rennstallwechsel ändern, soll ein Trigger geschrieben werden, mit dem das Gehalt des betreffenden Fahrers um 10\% angehoben wird. \index{ALTER TABLE} \index{TRIGGER} \begin{bAntwort} Lösung für PostgreSQL: \begin{minted}{sql} ALTER TABLE Fahrer ADD Gehalt numeric(12,2); UPDATE Fahrer SET Gehalt = 1000000 WHERE Fahrer_ID = 1; UPDATE Fahrer SET Gehalt = 2000000 WHERE Fahrer_ID = 2; UPDATE Fahrer SET Gehalt = 3000000 WHERE Fahrer_ID = 3; UPDATE Fahrer SET Gehalt = 4000000 WHERE Fahrer_ID = 4; UPDATE Fahrer SET Gehalt = 5000000 WHERE Fahrer_ID = 5; UPDATE Fahrer SET Gehalt = 6000000 WHERE Fahrer_ID = 6; UPDATE Fahrer SET Gehalt = 7000000 WHERE Fahrer_ID = 7; UPDATE Fahrer SET Gehalt = 8000000 WHERE Fahrer_ID = 8; UPDATE Fahrer SET Gehalt = 9000000 WHERE Fahrer_ID = 9; UPDATE Fahrer SET Gehalt = 10000000 WHERE Fahrer_ID = 10; CREATE FUNCTION trigger_function() RETURNS TRIGGER LANGUAGE PLPGSQL AS $$ BEGIN UPDATE Fahrer SET gehalt = gehalt * 1.1 WHERE Fahrer_ID = NEW.Fahrer_ID; RETURN NEW; END; $$; CREATE TRIGGER mehr_gehalt AFTER UPDATE OF Rennstall ON Fahrer FOR EACH ROW EXECUTE PROCEDURE trigger_function(); -- Test: SELECT * FROM FAHRER WHERE Fahrer_ID = 1; UPDATE Fahrer SET Rennstall = 'Red Bull' WHERE Fahrer_ID = 1; SELECT * FROM FAHRER WHERE Fahrer_ID = 1; \end{minted} \end{bAntwort} \end{enumerate} \end{document}