<?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>SQL-Jungle is a playful introduction to SQL. After crashing his plane in the jungle, the protagonist needs help from its inhabitants to find his way home.</teaser>
        <copyright>© 2023 Lily M. and Michèle B.</copyright>
    </head>
    <scenes>
        <text-scene>
            <text>SQL-Jungle is a playful introduction to SQL. After crashing his plane in the jungle, the protagonist needs help from its inhabitants to find his way home.</text>
        </text-scene>
        <text-scene>
            <text>Andy the monkey briefly explains to the protagonist what has happened and how he can leave the jungle. In return, he needs to help the villagers.

The villagers use a tablet to keep track of who owns each item and who wishes for something. The `residents` table contains humans and animal helpers. Each has a unique `code`. The `items.owner` column stores this code, for example `amonkey` for Andy. The `residents.wish` column names the desired item; `NULL` means no wish has been recorded. The protagonist can use SQL to look up the records and record agreed transfers.</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 tells the protagonist to start by looking up the villagers' names, roles, and wishes. Show all the details from `residents`: `code`, `name`, `species`, `role`, and `wish`. He offers a tip: “Use `SELECT *` and put the name of the table you want to view after `FROM`.”</text>
            <sql-solution>SELECT * FROM residents;</sql-solution>
            <sql-placeholder>SELECT *
FROM residents;</sql-placeholder>
            <hints>
                <text-hint>The asterisk in `SELECT *` stands for all columns. `FROM` specifies the table.</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>To get an idea of how long it will take before the protagonist can leave the jungle, he needs to count the recorded wishes. Return only their number. The animal helpers have no wish recorded. Tip: “Use `COUNT(wish)` in the `SELECT` clause! It counts the values in this column that are not `NULL`.”</text>
            <sql-solution>SELECT COUNT(wish) FROM residents;</sql-solution>
            <sql-placeholder>SELECT </sql-placeholder>
            <hints>
                <text-hint>Write `COUNT(wish)` after `SELECT` and `residents` after `FROM`. `COUNT(*)` would count all rows, including the animal helpers without a wish.</text-hint>
                <expected-result-hint />
            </hints>
        </select-scene>
        <text-scene>
            <text>Andy explains that the protagonist should fulfill the villagers' wishes in a particular order, ending with the chief, who will then help him leave the jungle. He also mentions that animals can help in some situations. First Susi, then Kristi, Kevin, and finally Hempter: that is their route through the village; the gifts are independent of one another. Each owner will be asked whether they are willing to give away their item.</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 the monkey says to start with Susi's wish. To fulfill it, the protagonist needs to find out everything about her. Show all the details from `residents` for Susi. Andy explains: “In addition to `SELECT` and `FROM`, you now need a `WHERE` clause. This is where you specify the conditions you need. Here, the condition is `name = 'Susi'`.”</text>
            <sql-solution>SELECT * FROM residents WHERE name = 'Susi';</sql-solution>
            <sql-placeholder>SELECT *
FROM residents
WHERE </sql-placeholder>
            <hints>
                <text-hint>Add `WHERE name = 'Susi'` to `SELECT * FROM residents`.</text-hint>
                <text-hint>Remember Susi's code and her wish. You will need both to record a transfer.</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>Now that the protagonist knows Susi's wish, he needs to find the current owner of the nuts. Show the current owner's `code`, `name`, and `species`. Andy the monkey explains: “Use a join to connect `items` with `residents`. The join condition is `items.owner = residents.code` and goes after `JOIN ... ON`. Use `WHERE` to select the item `Nuts`.” Return only the three specified columns.</text>
            <sql-solution>SELECT residents.code, residents.name, residents.species
FROM items
JOIN residents ON items.owner = residents.code
WHERE items.name = 'Nuts';</sql-solution>
            <sql-placeholder>SELECT residents.code, residents.name, residents.species
FROM items
JOIN residents ON </sql-placeholder>
            <hints>
                <text-hint>`FROM items JOIN residents ON items.owner = residents.code` connects each item with its owner. This relationship uses codes, not display names.</text-hint>
                <text-hint>Both tables have a column called `name`. Use `residents.name` to select the owner's name and `items.name` to select the item. Filter with `WHERE items.name = 'Nuts'`.</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>The nuts belong to Andy. Before the protagonist delivers the gifts, he needs an overview of all four wishes. For each wish, show the recipient's name, the name of the desired item, and its current owner's code. Join `residents.wish` with `items.name`. Return exactly these three columns; the order of the columns and rows does not matter.</text>
            <sql-solution>SELECT residents.name, items.name, items.owner
FROM residents
JOIN items ON residents.wish = items.name;</sql-solution>
            <sql-placeholder>SELECT residents.name, items.name, items.owner
FROM residents
JOIN items ON </sql-placeholder>
            <hints>
                <text-hint>Here you connect a wish with the matching item, so `residents` refers to the recipients. In the previous task, you looked for the owners instead.</text-hint>
                <text-hint>Use `FROM residents JOIN items ON residents.wish = items.name`. Residents without a wish have no matching item and do not appear in this `JOIN`.</text-hint>
                <text-hint>Select `residents.name`, `items.name`, and `items.owner`. The query should include all four wishes, without filtering for a single person.</text-hint>
                <expected-result-hint />
            </hints>
        </select-scene>
        <manipulate-scene has-sol-hint="true">
            <text>Next, the protagonist needs to persuade the current owner of the nuts to give them to Susi. “Susi is welcome to have my nuts,” says Andy. To record this, change the current owner to Susi's code: only the item `Nuts` should now have `sus` in `owner`. Andy says: “Since this is a little harder, here's a tip: `UPDATE` selects the table, `SET` specifies the new value, and `WHERE` selects the affected item.” All other items and all the details in `residents` must remain unchanged. Andy adds: “Without `WHERE`, you change every row. First use `SELECT` to check which item your condition selects.”</text>
            <sql-solution>UPDATE items
SET owner = 'sus'
WHERE name = 'Nuts';</sql-solution>
            <sql-check>SELECT * FROM items;
SELECT * FROM residents;</sql-check>
            <sql-placeholder>-- Record only the agreed transfer.
UPDATE items
SET owner = </sql-placeholder>
            <hints>
                <text-hint>`UPDATE items SET owner = 'sus' WHERE name = 'Nuts';` records this one transfer.</text-hint>
                <text-hint>Andy also owns a leaf. `WHERE owner = 'amonkey'` would transfer both items. Select the item by its unique name instead.</text-hint>
                <expected-result-hint />
            </hints>
        </manipulate-scene>
        <manipulate-scene has-sol-hint="true">
            <text>The protagonist still needs to fulfill the remaining wishes, in the order Kristi, then Kevin, and finally Hempter. Repeat the previous process with the right details for each person until the last wish is fulfilled. Start with Kristi and write the appropriate `UPDATE` statement. Berta the mountain goat offers to give Kristi the chamomile for her herb supplies; she is keeping her pebble. If needed, look up Kristi's wish and code in `residents`. Change the owner to Kristi's code only for the desired item.</text>
            <sql-solution>UPDATE items
SET owner = 'healerk'
WHERE name = 'Chamomile';</sql-solution>
            <sql-check>SELECT * FROM items;
SELECT * FROM residents;</sql-check>
            <sql-placeholder>-- Record only the agreed transfer.
UPDATE items
SET owner = </sql-placeholder>
            <hints>
                <text-hint>Use `SELECT wish, code FROM residents WHERE name = 'Kristi';` to look up the wish and recipient's code. You may run a lookup query like this; only the correct transfer solves the task.</text-hint>
                <text-hint>The query returns Chamomile and healerk. Use the item in `WHERE` and the code in `SET`.</text-hint>
                <text-hint>`UPDATE items SET owner = 'healerk' WHERE name = 'Chamomile';` changes only the desired item.</text-hint>
                <expected-result-hint />
            </hints>
        </manipulate-scene>
        <manipulate-scene has-sol-hint="true">
            <text>Kevin is next. Repeat the previous process and write the appropriate `UPDATE` statement. Kristi is happy to give Kevin her flower. Record only this transfer: the flower should now belong to Kevin. Kristi's chamomile and bag, and all other data, must remain unchanged.</text>
            <sql-solution>UPDATE items
SET owner = 'kevtheboss'
WHERE name = 'Flower';</sql-solution>
            <sql-check>SELECT * FROM items;
SELECT * FROM residents;</sql-check>
            <sql-placeholder>-- Record only the agreed transfer.
UPDATE items
SET owner = </sql-placeholder>
            <hints>
                <text-hint>Find Kevin's code with `SELECT code FROM residents WHERE name = 'Kevin'`.</text-hint>
                <text-hint>The code kevtheboss belongs to Kevin. Filter `items` by the name Flower so that Kristi keeps her other items.</text-hint>
                <expected-result-hint />
            </hints>
        </manipulate-scene>
        <manipulate-scene has-sol-hint="true">
            <text>Finally, Hempter. Repeat the previous process and write the appropriate `UPDATE` statement. Siegfried the snake offers Hempter his spear for fishing and keeps his branch. Record Hempter as the new owner of the spear only. Use his code from `residents`; all other data must remain unchanged.</text>
            <sql-solution>UPDATE items
SET owner = 'chiefh'
WHERE name = 'Spear';</sql-solution>
            <sql-check>SELECT * FROM items;
SELECT * FROM residents;</sql-check>
            <sql-placeholder>-- Record only the agreed transfer.
UPDATE items
SET owner = </sql-placeholder>
            <hints>
                <text-hint>Use `SELECT code, wish FROM residents WHERE name = 'Hempter';` to find the recipient and item.</text-hint>
                <text-hint>Hempter's code is chiefh. Select the spear with `WHERE name = 'Spear'`.</text-hint>
                <expected-result-hint />
            </hints>
        </manipulate-scene>
        <text-scene>
            <text>The protagonist now stands before the chief, who thanks him for fulfilling all the wishes and explains the way out of the jungle. Susi has the nuts, Kristi the chamomile, Kevin the flower, and Hempter the spear. Andy accompanies the protagonist to the landing stage by the river. A supply boat takes him to the nearest town, where he arranges his journey home.</text>
        </text-scene>
        <text-scene>
            <text>By (hopefully) completing SQL-Jungle successfully, you have become familiar with the basics of SQL and learned how to use joins and aggregate functions. You also know how to change records. When making changes, pay particular attention to `WHERE` so that only the intended rows are changed.</text>
        </text-scene>
    </scenes>
    <initial-sql-script>PRAGMA foreign_keys = ON;

CREATE TABLE residents (
    code TEXT PRIMARY KEY NOT NULL,
    name TEXT NOT NULL,
    species TEXT NOT NULL,
    role TEXT NOT NULL,
    wish TEXT REFERENCES items(name)
);

CREATE TABLE items (
    name TEXT PRIMARY KEY NOT NULL,
    owner TEXT NOT NULL REFERENCES residents(code)
);

INSERT INTO residents VALUES ('amonkey', 'Andy', 'Monkey', 'Companion', NULL);
INSERT INTO residents VALUES ('mountaingoat', 'Berta', 'Mountain goat', 'Helper', NULL);
INSERT INTO residents VALUES ('sssnake', 'Siegfried', 'Snake', 'Helper', NULL);
INSERT INTO residents VALUES ('healerk', 'Kristi', 'Human', 'Healer', NULL);
INSERT INTO residents VALUES ('chiefh', 'Hempter', 'Human', 'Village chief', NULL);
INSERT INTO residents VALUES ('sus', 'Susi', 'Human', 'Child', NULL);
INSERT INTO residents VALUES ('kevtheboss', 'Kevin', 'Human', 'Child', NULL);

INSERT INTO items VALUES ('Chamomile', 'mountaingoat');
INSERT INTO items VALUES ('Flower', 'healerk');
INSERT INTO items VALUES ('Spear', 'sssnake');
INSERT INTO items VALUES ('Nuts', 'amonkey');
INSERT INTO items VALUES ('Leaf', 'amonkey');
INSERT INTO items VALUES ('Pebble', 'mountaingoat');
INSERT INTO items VALUES ('Branch', 'sssnake');
INSERT INTO items VALUES ('Bag', 'healerk');

UPDATE residents SET wish = 'Chamomile' WHERE code = 'healerk';
UPDATE residents SET wish = 'Spear' WHERE code = 'chiefh';
UPDATE residents SET wish = 'Nuts' WHERE code = 'sus';
UPDATE residents SET wish = 'Flower' WHERE code = 'kevtheboss';
</initial-sql-script>
</game>
