<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<game format-version="2" db-system="sqlite" db-system-min-version="3.37.0">
    <head>
        <title>SQL-Jungle</title>
        <teaser>In SQL-Jungle lernt man spielerisch den Umgang mit SQL. Der Protagonist ist mit seinem Flugzeug im Jungle abgestürzt und braucht Hilfe von dessen Bewohnern, um wieder nach Hause zu kommen.</teaser>
        <copyright>© 2023 Lily M. und Michèle B.</copyright>
    </head>
    <scenes>
        <text-scene>
            <text>In SQL-Jungle lernt man spielerisch den Umgang mit SQL. Der Protagonist ist mit seinem Flugzeug im Jungle abgestürzt und braucht Hilfe von dessen Bewohnern, um wieder nach Hause zu kommen.</text>
        </text-scene>
        <text-scene>
            <text>Der Protagonist bekommt eine kurze Erklärung von Affe Andy dafür, was passiert ist und wie er den Jungle wieder verlassen kann. Er muss dafür im Gegenzug irgendwie den Ureinwohnern helfen.

Die Dorfbewohner halten auf einem Tablet fest, wem die Gegenstände gehören und wer sich etwas wünscht. Die Tabelle `bewohner` enthält Menschen und tierische Helfer. Jeder hat ein eindeutiges `kuerzel`. In `objekt.besitzer` steht dieses Kürzel, zum Beispiel `aaffe` für Andy. `bewohner.wunsch` nennt den gewünschten Gegenstand; `NULL` bedeutet, dass kein Wunsch eingetragen ist. Mit SQL kann der Protagonist die Einträge nachsehen und vereinbarte Übergaben festhalten.</text>
        </text-scene>
        <select-scene is-row-order-relevant="false" is-col-order-relevant="false" are-col-names-relevant="false" has-sol-hint="true">
            <text>Andy sagt dem Protagonisten, er solle erst einmal nachsehen, wie die Dorfbewohner heißen, welche Stellung und Wünsche sie haben. Zeige alle Angaben aus `bewohner`: Kürzel, Name, Art, Stellung und Wunsch. Als Tipp gibt er ihm: „Benutze hierzu `SELECT *` und gib bei `FROM` den Namen der Relation an, welche du einsehen möchtest.“</text>
            <sql-solution>SELECT * FROM bewohner;</sql-solution>
            <sql-placeholder>SELECT *
FROM bewohner;</sql-placeholder>
            <hints>
                <text-hint>Der Stern in `SELECT *` steht für alle Spalten. `FROM` bestimmt die Tabelle.</text-hint>
                <expected-result-hint />
            </hints>
        </select-scene>
        <select-scene is-row-order-relevant="false" is-col-order-relevant="false" are-col-names-relevant="false" has-sol-hint="true">
            <text>Um einen Überblick zu bekommen, wie lange es dauern wird, bis der Protagonist den Jungle wieder verlassen kann, muss er die eingetragenen Wünsche zählen. Gib nur ihre Anzahl aus. Die tierischen Helfer haben keinen Wunsch eingetragen. Tipp: „Nutze `COUNT(wunsch)` in der `SELECT`-Klausel! Das zählt die Werte in dieser Spalte, die nicht `NULL` sind.“</text>
            <sql-solution>SELECT COUNT(wunsch) FROM bewohner;</sql-solution>
            <sql-placeholder>SELECT </sql-placeholder>
            <hints>
                <text-hint>Schreibe `COUNT(wunsch)` hinter `SELECT` und `bewohner` hinter `FROM`. `COUNT(*)` würde dagegen alle Zeilen zählen, auch die tierischen Helfer ohne Wunsch.</text-hint>
                <expected-result-hint />
            </hints>
        </select-scene>
        <text-scene>
            <text>Andy erklärt, dass der Protagonist die Wünsche der Ureinwohner am besten in einer bestimmten Reihenfolge erfüllen sollte, damit er am Ende dem Häuptling helfen kann, der wiederum ihm aus dem Jungle helfen wird. Außerdem erwähnt er, dass auch Tiere ihm in einigen Situationen weiterhelfen können. Zuerst Susi, dann Kristi, Kevin und zuletzt Hempter: Das ist ihre Route durchs Dorf; die Geschenke sind voneinander unabhängig. Die jeweiligen Besitzer werden gefragt, ob sie ihren Gegenstand abgeben möchten.</text>
        </text-scene>
        <select-scene is-row-order-relevant="false" is-col-order-relevant="false" are-col-names-relevant="false" has-sol-hint="true">
            <text>Der Affe Andy sagt, dass er mit Susis Wunsch beginnen sollte. Um diesen zu erfüllen, muss er alles über sie herausfinden. Zeige alle Angaben aus `bewohner` für Susi. Dafür erklärt Andy außerdem: „Hierfür kommt zu `SELECT` und `FROM` auch noch die `WHERE`-Klausel. Dort gibst du einfach die Bedingungen ein, die gebraucht werden. Hier wäre dies `name = 'Susi'`.“</text>
            <sql-solution>SELECT * FROM bewohner WHERE name = 'Susi';</sql-solution>
            <sql-placeholder>SELECT *
FROM bewohner
WHERE </sql-placeholder>
            <hints>
                <text-hint>Ergänze `SELECT * FROM bewohner` um `WHERE name = 'Susi'`.</text-hint>
                <text-hint>Merke dir Susis Kürzel und ihren Wunsch. Für eine Übergabe brauchst du beides.</text-hint>
                <expected-result-hint />
            </hints>
        </select-scene>
        <select-scene is-row-order-relevant="false" is-col-order-relevant="false" are-col-names-relevant="false" has-sol-hint="true">
            <text>Jetzt, wo der Protagonist den Wunsch von Susi weiß, muss er den derzeitigen Besitzer der Nüsse herausfinden. Zeige Kürzel, Name und Art des aktuellen Besitzers. Hier erklärt Affe Andy: „Benutze einen Join, indem du `objekt` mit `bewohner` verbindest. Die Join-Bedingung lautet `objekt.besitzer = bewohner.kuerzel` und steht hinter `JOIN ... ON`. Mit `WHERE` wählst du das Objekt `Nüsse` aus.“ Gib nur die drei genannten Spalten aus.</text>
            <sql-solution>SELECT bewohner.kuerzel, bewohner.name, bewohner.art
FROM objekt
JOIN bewohner ON objekt.besitzer = bewohner.kuerzel
WHERE objekt.name = 'Nüsse';</sql-solution>
            <sql-placeholder>SELECT bewohner.kuerzel, bewohner.name, bewohner.art
FROM objekt
JOIN bewohner ON </sql-placeholder>
            <hints>
                <text-hint>`FROM objekt JOIN bewohner ON objekt.besitzer = bewohner.kuerzel` verbindet jeden Gegenstand mit seinem Besitzer. Die Beziehung verwendet Kürzel, keine Anzeigenamen.</text-hint>
                <text-hint>Beide Tabellen haben eine Spalte `name`. Mit `bewohner.name` wählst du den Namen des Besitzers, mit `objekt.name` den Gegenstand. Filtere mit `WHERE objekt.name = 'Nüsse'`.</text-hint>
                <expected-result-hint />
            </hints>
        </select-scene>
        <select-scene is-row-order-relevant="false" is-col-order-relevant="false" are-col-names-relevant="false" has-sol-hint="true">
            <text>Die Nüsse gehören Andy. Bevor der Protagonist die Geschenke überbringt, braucht er eine Übersicht für alle vier Wünsche. Zeige jeweils den Namen des Empfängers, den Namen des gewünschten Gegenstands und das Kürzel seines aktuellen Besitzers. Verbinde dazu `bewohner.wunsch` mit `objekt.name`. Gib genau diese drei Spalten aus; ihre Reihenfolge und die Reihenfolge der Zeilen sind beliebig.</text>
            <sql-solution>SELECT bewohner.name, objekt.name, objekt.besitzer
FROM bewohner
JOIN objekt ON bewohner.wunsch = objekt.name;</sql-solution>
            <sql-placeholder>SELECT bewohner.name, objekt.name, objekt.besitzer
FROM bewohner
JOIN objekt ON </sql-placeholder>
            <hints>
                <text-hint>Hier verknüpfst du einen Wunsch mit dem passenden Gegenstand. `bewohner` bezeichnet deshalb die Empfänger. In der vorigen Aufgabe hast du stattdessen die Besitzer gesucht.</text-hint>
                <text-hint>Verwende `FROM bewohner JOIN objekt ON bewohner.wunsch = objekt.name`. Bewohner ohne Wunsch haben keinen passenden Gegenstand und erscheinen bei diesem `JOIN` nicht.</text-hint>
                <text-hint>Wähle `bewohner.name`, `objekt.name` und `objekt.besitzer`. Die Abfrage soll alle vier Wünsche enthalten, ohne Filter auf eine einzelne Person.</text-hint>
                <expected-result-hint />
            </hints>
        </select-scene>
        <manipulate-scene has-sol-hint="true">
            <text>Danach muss der Protagonist den momentanen Besitzer der Nüsse davon überzeugen, die Nüsse an Susi abzugeben. „Susi kann meine Nüsse gern haben“, sagt Andy. Dafür ändern wir den jetzigen Besitzer zu Susis Kürzel: Nur beim Gegenstand `Nüsse` muss in `besitzer` nun `sus` stehen. Andy sagt: „Da dies etwas schwerer ist, gebe ich dir einen Tipp: `UPDATE` wählt die Tabelle, `SET` den neuen Wert und `WHERE` den betroffenen Gegenstand.“ Alle anderen Gegenstände und sämtliche Angaben in `bewohner` sollen unverändert bleiben. Andy ergänzt: „Ohne `WHERE` änderst du alle Zeilen. Prüfe zuerst mit `SELECT`, welchen Gegenstand deine Bedingung auswählt.“</text>
            <sql-solution>UPDATE objekt
SET besitzer = 'sus'
WHERE name = 'Nüsse';</sql-solution>
            <sql-check>SELECT * FROM objekt;
SELECT * FROM bewohner;</sql-check>
            <sql-placeholder>-- Trage nur die vereinbarte Übergabe ein.
UPDATE objekt
SET besitzer = </sql-placeholder>
            <hints>
                <text-hint>`UPDATE objekt SET besitzer = 'sus' WHERE name = 'Nüsse';` trägt diese eine Übergabe ein.</text-hint>
                <text-hint>Andy besitzt auch ein Blatt. `WHERE besitzer = 'aaffe'` würde beide Gegenstände übertragen. Wähle deshalb den Gegenstand über seinen eindeutigen Namen aus.</text-hint>
                <expected-result-hint />
            </hints>
        </manipulate-scene>
        <manipulate-scene has-sol-hint="true">
            <text>Nun muss der Protagonist noch die restlichen Wünsche erfüllen. Dies soll er in der Reihenfolge Kristi, dann Kevin und zuletzt Hempter machen. Wiederhole also den Vorgang von gerade mit den richtigen Daten für die jeweiligen Personen, bis du den letzten Wunsch erfüllt hast. Beginne nun mit Kristi und formuliere anschließend die passende `UPDATE`-Anfrage. Die Bergziege Berta bietet an, die Kamille für Kristis Kräutervorrat abzugeben; ihren Kiesel behält sie. Sieh bei Bedarf in `bewohner` nach, welchen Wunsch und welches Kürzel Kristi hat. Ändere nur beim gewünschten Gegenstand den Besitzer auf Kristis Kürzel.</text>
            <sql-solution>UPDATE objekt
SET besitzer = 'heilerk'
WHERE name = 'Kamille';</sql-solution>
            <sql-check>SELECT * FROM objekt;
SELECT * FROM bewohner;</sql-check>
            <sql-placeholder>-- Trage nur die vereinbarte Übergabe ein.
UPDATE objekt
SET besitzer = </sql-placeholder>
            <hints>
                <text-hint>Mit `SELECT wunsch, kuerzel FROM bewohner WHERE name = 'Kristi';` kannst du Wunsch und Empfängerkürzel nachsehen. Eine solche Nachfrage ist erlaubt; erst die passende Übergabe löst die Aufgabe.</text-hint>
                <text-hint>Die Auswahl liefert Kamille und heilerk. Verwende den Gegenstand in `WHERE` und das Kürzel in `SET`.</text-hint>
                <text-hint>`UPDATE objekt SET besitzer = 'heilerk' WHERE name = 'Kamille';` ändert nur den gewünschten Gegenstand.</text-hint>
                <expected-result-hint />
            </hints>
        </manipulate-scene>
        <manipulate-scene has-sol-hint="true">
            <text>Weiter geht es mit Kevin. Wiederhole also den Vorgang von gerade und formuliere anschließend die passende `UPDATE`-Anfrage. Kristi schenkt Kevin gern ihre Blume. Trage nur diese Übergabe ein: Die Blume soll anschließend Kevin gehören. Kristis Kamille und Tasche sowie alle übrigen Daten sollen unverändert bleiben.</text>
            <sql-solution>UPDATE objekt
SET besitzer = 'kevderboss'
WHERE name = 'Blume';</sql-solution>
            <sql-check>SELECT * FROM objekt;
SELECT * FROM bewohner;</sql-check>
            <sql-placeholder>-- Trage nur die vereinbarte Übergabe ein.
UPDATE objekt
SET besitzer = </sql-placeholder>
            <hints>
                <text-hint>Kevins Kürzel findest du mit `SELECT kuerzel FROM bewohner WHERE name = 'Kevin'`.</text-hint>
                <text-hint>Das Kürzel kevderboss gehört Kevin. Filtere in `objekt` nach dem Namen Blume, damit Kristis übrige Gegenstände erhalten bleiben.</text-hint>
                <expected-result-hint />
            </hints>
        </manipulate-scene>
        <manipulate-scene has-sol-hint="true">
            <text>Abschließend noch Hempter. Wiederhole also den Vorgang von gerade und formuliere anschließend die passende `UPDATE`-Anfrage. Die Schlange Siegfried bietet Hempter ihren Speer zum Fischen an und behält ihren Ast. Trage nur für den Speer Hempter als neuen Besitzer ein. Verwende sein Kürzel aus `bewohner`; alle anderen Daten sollen unverändert bleiben.</text>
            <sql-solution>UPDATE objekt
SET besitzer = 'haeuptlingh'
WHERE name = 'Speer';</sql-solution>
            <sql-check>SELECT * FROM objekt;
SELECT * FROM bewohner;</sql-check>
            <sql-placeholder>-- Trage nur die vereinbarte Übergabe ein.
UPDATE objekt
SET besitzer = </sql-placeholder>
            <hints>
                <text-hint>Mit `SELECT kuerzel, wunsch FROM bewohner WHERE name = 'Hempter';` findest du Empfänger und Gegenstand.</text-hint>
                <text-hint>Hempters Kürzel ist haeuptlingh. Wähle den Speer mit `WHERE name = 'Speer'` aus.</text-hint>
                <expected-result-hint />
            </hints>
        </manipulate-scene>
        <text-scene>
            <text>Nun steht der Protagonist vor dem Häuptling, der ihm aus Dankbarkeit, dass er alle Wünsche erfüllt hat, den Weg aus dem Jungle erklärt. Susi hat die Nüsse, Kristi die Kamille, Kevin die Blume und Hempter den Speer. Andy begleitet den Protagonisten zur Anlegestelle am Fluss. Ein Versorgungsboot nimmt ihn in den nächsten Ort mit. Von dort organisiert er seine Heimreise.</text>
        </text-scene>
        <text-scene>
            <text>Mit dem (hoffentlich) erfolgreichen Beenden des SQL-Jungle-Spiels bist du mit den Basics der Abfragesprache SQL vertraut und hast auch gelernt, wie man Joins und Aggregationen verwendet. Als Zusatz weißt du auch, wie man Datensätze ändern kann. Besonders bei Änderungen lohnt sich ein genauer Blick auf `WHERE`, damit nur die beabsichtigten Zeilen geändert werden.</text>
        </text-scene>
    </scenes>
    <initial-sql-script>PRAGMA foreign_keys = ON;

CREATE TABLE bewohner (
    kuerzel TEXT PRIMARY KEY NOT NULL,
    name TEXT NOT NULL,
    art TEXT NOT NULL,
    stellung TEXT NOT NULL,
    wunsch TEXT REFERENCES objekt(name)
);

CREATE TABLE objekt (
    name TEXT PRIMARY KEY NOT NULL,
    besitzer TEXT NOT NULL REFERENCES bewohner(kuerzel)
);

INSERT INTO bewohner VALUES ('aaffe', 'Andy', 'Affe', 'Wegbegleiter', NULL);
INSERT INTO bewohner VALUES ('ziegenberg', 'Berta', 'Bergziege', 'Helferin', NULL);
INSERT INTO bewohner VALUES ('ssschlange', 'Siegfried', 'Schlange', 'Helfer', NULL);
INSERT INTO bewohner VALUES ('heilerk', 'Kristi', 'Mensch', 'Heiler', NULL);
INSERT INTO bewohner VALUES ('haeuptlingh', 'Hempter', 'Mensch', 'Dorfvorsteher', NULL);
INSERT INTO bewohner VALUES ('sus', 'Susi', 'Mensch', 'Kind', NULL);
INSERT INTO bewohner VALUES ('kevderboss', 'Kevin', 'Mensch', 'Kind', NULL);

INSERT INTO objekt VALUES ('Kamille', 'ziegenberg');
INSERT INTO objekt VALUES ('Blume', 'heilerk');
INSERT INTO objekt VALUES ('Speer', 'ssschlange');
INSERT INTO objekt VALUES ('Nüsse', 'aaffe');
INSERT INTO objekt VALUES ('Blatt', 'aaffe');
INSERT INTO objekt VALUES ('Kiesel', 'ziegenberg');
INSERT INTO objekt VALUES ('Ast', 'ssschlange');
INSERT INTO objekt VALUES ('Tasche', 'heilerk');

UPDATE bewohner SET wunsch = 'Kamille' WHERE kuerzel = 'heilerk';
UPDATE bewohner SET wunsch = 'Speer' WHERE kuerzel = 'haeuptlingh';
UPDATE bewohner SET wunsch = 'Nüsse' WHERE kuerzel = 'sus';
UPDATE bewohner SET wunsch = 'Blume' WHERE kuerzel = 'kevderboss';
</initial-sql-script>
</game>
