\documentclass{bschlangaul-aufgabe}
\bLadePakete{rmodell,syntax}
\begin{document}
\bAufgabenMetadaten{
  Titel = {Aufgabe 4},
  Thematik = {Triathlon},
  Referenz = 66116-2018-H.T1-TA2-A4,
  RelativerPfad = Examen/66116/2018/09/Thema-1/Teilaufgabe-2/Aufgabe-4.tex,
  ZitatSchluessel = examen:66116:2018:09,
  BearbeitungsStand = mit Lösung,
  Korrektheit = unbekannt,
  Ueberprueft = {unbekannt},
  Stichwoerter = {SQL mit Übungsdatenbank, SQL, UPDATE, DESC, AVG, GROUP BY, HAVING, EXCEPT},
  EinzelpruefungsNr = 66116,
  Jahr = 2018,
  Monat = 09,
  ThemaNr = 1,
  TeilaufgabeNr = 2,
  AufgabeNr = 4,
}

\let\a=\bAttribut
\let\f=\bFremd
\let\p=\bPrimaer
\let\r=\bRelationMenge

Gegeben sind folgende Relationen aus einer Datenbank zur Verwaltung von
Triathlon-Wettbewerben.

% Athlet (ID, Vorname, Nachname)

% Ergebnis (Athlet [Athlet], Wettbewerb [Wettbewerb], Schwimmzeit, Radzeit,
% Laufzeit); Schwimmzeit NOT NULL

% Wettbewerb (Name, Jahr)

\begin{bProjektSprache}{RelationenSchema}
Athlet (ID*, Vorname, Nachname)
Ergebnis (Athlet[Athlet]*, Wettbewerb[Wettbewerb]*, Schwimmzeit {NOT NULL}, Radzeit, Laufzeit)
Wettbewerb (Name*, Jahr)
\end{bProjektSprache}

\begin{bRelationenModell}
\r{Athlet}{\p{ID}, Vorname, Nachname}
\r{Ergebnis}{\p{Athlet[Athlet]}, \f{Wettbewerb[Wettbewerb]}, Schwimmzeit, Radzeit, Laufzeit}
\r{Wettbewerb}{\p{Name}, Jahr}
\end{bRelationenModell}

% Datenbankname: db
\begin{minted}{sql}
CREATE TABLE Athlet (
  ID INTEGER PRIMARY KEY,
  Vorname VARCHAR(20),
  Nachname VARCHAR(20)
);

CREATE TABLE Wettbewerb (
  Name VARCHAR(40) PRIMARY KEY,
  Jahr INTEGER
);

CREATE TABLE Ergebnis (
  Athlet INTEGER REFERENCES Athlet(ID),
  Wettbewerb VARCHAR(40) REFERENCES Wettbewerb(Name),
  Schwimmzeit INTEGER NOT NULL,
  Radzeit INTEGER,
  Laufzeit INTEGER,
  PRIMARY KEY (Athlet, Wettbewerb)
);

INSERT INTO Athlet VALUES
  (1, 'Boris', 'Stein'),
  (2, 'Trevor', 'Wurtele'),
  (3, 'Reichelt', 'Horst'),
  (12, 'Mitch', 'Kibby');

INSERT INTO Wettbewerb VALUES
  ('Zürichsee', 2018),
  ('Ironman Vichy', 2018),
  ('Challenge Walchsee', 2018),
  ('Triathlon Alpe d’Huez', 2017);

INSERT INTO Ergebnis VALUES
  (1, 'Zürichsee', 14, 10, 11),
  (2, 'Zürichsee', 13, 10, 11),
  (3, 'Zürichsee', 12, 10, 11),
  (12, 'Zürichsee', 11, 10, 11),
  (2, 'Challenge Walchsee', 12, 10, 11),
  (3, 'Challenge Walchsee', 11, 10, 11),
  (12, 'Triathlon Alpe d’Huez', 9, 10, 11);
\end{minted}
\index{SQL mit Übungsdatenbank}

\noindent
Verwenden Sie im Folgenden nur Standard-SQL und keine
produktspezifischen Erweiterungen. Sie dürfen bei Bedarf Views anlegen.
Geben Sie einen Datensatz, also eine Entity, nicht mehrfach aus.
\index{SQL}
\footcite{examen:66116:2018:09}

\begin{enumerate}

%%
% a)
%%

\item Schreiben Sie eine SQL-Anweisung, die die Tabelle „Ergebnis“
anlegt. Gehen Sie davon aus, dass die Tabellen „Athlet“ und
„Wettbewerb“ bereits existieren. Verwenden Sie sinnvolle Datentypen.

\begin{bAntwort}
\begin{minted}{sql}
CREATE TABLE IF NOT EXISTS Ergebnis (
  Athlet INTEGER REFERENCES Athlet(ID),
  Wettbewerb INTEGER REFERENCES Wettbewerb(Name),
  Schwimmzeit INTEGER NOT NULL,
  Radzeit INTEGER,
  Laufzeit INTEGER,
  PRIMARY KEY (Athlet, Wettbewerb)
);
\end{minted}

% CREATE TABLE Ergebnis(
% Athlet INTEGER REFERENCES Athlet(ID),
% Wettbewer VARCHAR(50) REFERENCES Wettbewerb(Name),
% Schwimmzeit FLOAT NOT NULL,
% Radzeit FLOAT,
% Laufzeit FLOAT);
\end{bAntwort}

%%
% b)
%%

\item Schreiben Sie eine SQL-Anweisung, die die Radzeit des Teilnehmers
mit der ID 12 beim Wettbewerb „Zürichsee“ um eins erhöht.
\index{UPDATE}

\begin{bAntwort}
\begin{minted}{sql}
-- Nur für Test-Zwecke
SELECT * FROM Ergebnis WHERE Athlet = 12 AND Wettbewerb = 'Zürichsee';

UPDATE Ergebnis
SET Radzeit = Radzeit + 1
WHERE Athlet = 12 AND Wettbewerb = 'Zürichsee';

-- Nur für Test-Zwecke
SELECT * FROM Ergebnis WHERE Athlet = 12 AND Wettbewerb = 'Zürichsee';
\end{minted}
\end{bAntwort}

%%
% c)
%%

\item Schreiben Sie eine SQL-Anweisung, die die Namen aller Wettbewerbe
des Jahres 2018 ausgibt, absteigend sortiert nach Name.
\index{DESC}

\begin{bAntwort}
\begin{minted}{sql}
SELECT Name
FROM Wettbewerb
WHERE Jahr = 2018
ORDER BY Name DESC;
\end{minted}
\end{bAntwort}

%%
% d)
%%

\item Schreiben Sie eine SQL-Anweisung, die die Namen aller Wettbewerbe
ausgibt, in der die durchschnittliche Schwimmzeit größer als 10 ist.
\index{AVG}\index{GROUP BY}\index{HAVING}

\begin{bAntwort}
\begin{minted}{sql}
SELECT Wettbewerb, AVG(Schwimmzeit)
FROM Ergebnis
GROUP BY Wettbewerb
HAVING AVG(Schwimmzeit) > 10;
\end{minted}
\end{bAntwort}

%%
% e)
%%

\item Schreiben Sie eine SQL-Anweisung, die die IDs aller Athleten
ausgibt, die im Jahr 2017 an keinem Wettbewerb teilgenommen haben.
\index{EXCEPT}

\begin{bAntwort}
\begin{minted}{sql}
(SELECT DISTINCT Athlet FROM Ergebnis)
EXCEPT
(SELECT DISTINCT Athlet FROM Ergebnis e, Wettbewerb w
WHERE e.Wettbewerb = w.name AND w.Jahr = 2017);
\end{minted}
\end{bAntwort}

%%
% f)
%%

\item Schreiben Sie eine SQL-Anweisung, die die Nachnamen aller Athleten
ausgibt, die mindestens 10 Wettbewerbe gewonnen haben, das heißt im
jeweiligen Wettbewerb die kürzeste Gesamtzeit erreicht haben. Die
Gesamtzeit ist die Summe aus Schwimmzeit, Radzeit und Laufzeit. Falls
zwei Athleten in einem Wettbewerb die gleiche Gesamtzeit erreichen, sind
beide Sieger.

\begin{bAntwort}
vermutlich falsch
\begin{minted}{sql}
CREATE VIEW Gesamtzeiten AS
SELECT e.Athlet AS NameAthlet, e.Radzeit + e.Schwimmzeit + e.Laufzeit
AS Gesamtzeit, w.NameWettbewerb
FROM Ergebnis e, Wettbewerb w
WHERE e.Wettbewerb = w.Name
CREATE VIEW Sieger AS
SELECT g1.NameAthlet
FROM Gesamtzeiten g1, Gesamtzeiten g2
GROUP BY g1.NameWettbewerb
HAVING g1.Gesamtzeit < g2.Gesamtzeit
SELECT NameAthlet
FROM Sieger
GROUP BY NameAthlet
HAVING count(*) > 10;
\end{minted}
\end{bAntwort}

%%
% g)
%%

\item Schreiben Sie eine SQL-Anweisung, die die Top-Ten der Athleten mit
der schnellsten Schwimmzeit des Wettbewerbs „Paris“ ausgibt. Ausgegeben
werden sollen die Platzierung (1 bis 10) und der Nachname des Athleten,
aufsteigend sortiert nach Platzierung. Gehen Sie davon aus, dass keine
zwei Athleten die gleiche Schwimmzeit haben und verwenden Sie keine
produktspezifischen Anweisungen wie beispielsweise rownum, top oder
limit.

\begin{bAntwort}
\begin{minted}{sql}
CREATE VIEW AthletenParis AS
SELECT a.Nachname, e.Schwimmzeit
FROM Athlet a, Ergebnis e INNER JOIN Wettbewerb W ON e.Wettbewerb = w.Name
WHERE w.Name = "Paris" AND a.ID = e.Athlet
SELECT a.Nachname COUNT(*) + 1 AS Platzierung
FROM AthletenParis a, AthletenParis b
WHERE a.Schwimmzeit < b.Schwimmzeit
GROUP BY a.Nachname
HAVING Platzierung <= 10;
\end{minted}
\end{bAntwort}

%%
% h)
%%

\item Schreiben Sie einen Trigger, der beim Einfügen neuer Tupel in die
Tabelle „Ergebnis“ die Schwimmzeit auf den Wert 0 setzt, falls diese
negativ ist.

\begin{bAntwort}
\begin{minted}{sql}
CREATE TRIGGER update_Ergebnis AFTER UPDATE ON Ergebnis AS
IF(UPDATE Schwimmzeit AND Schwimmzeit < 0) BEGIN UPDATE Ergebnis
SET Schwimmzeit = 0
WHERE (Athlet, Wettbewerb) IN (SELECT DISTINCT (Athlet, Wettbewerb) FROM inserted)
END;
\end{minted}
\end{bAntwort}

\end{enumerate}

\end{document}
