DEV Community

Cover image for SQL Murder Mystery, SQL Island & Gamified SQL Practice Walkthrough
Gowtham Potureddi
Gowtham Potureddi

Posted on

SQL Murder Mystery, SQL Island & Gamified SQL Practice Walkthrough

SQL Murder Mystery, SQL Island & Gamified SQL Practice Walkthrough

sql murder mystery and sql island are the two free browser games that quietly rescued more bored SQL students than any textbook published since 2010. One is a noir detective story where every clue is a SELECT, the other is a desert-island escape where every quest unlocks the next JOIN. Both work because they swap the dull "list of exercises" UX of a typical SQL tutorial for a story with a beginning, a middle, and a satisfying "case solved" / "raft built" payoff at the end.

This walkthrough is the cheat sheet you wished existed before you opened the first clue. It plays both games end-to-end, maps every step to a teaching concept (WHERE, JOIN, GROUP BY, HAVING, ORDER BY, basic DML), compares them with the broader gamified SQL landscape (Schemaverse, CodingGame SQL puzzles, Lost at SQL), and ends with a skill-progression map that shows the honest ceiling — narrative SQL is brilliant for the first 30% of the language, but window functions, CTEs, and company-flavoured interview problems need targeted practice that no game currently delivers.

PipeCode blog header for a SQL Murder Mystery & SQL Island gamified practice walkthrough — bold white headline 'SQL Murder Mystery · SQL Island' with subtitle 'Gamified SQL practice — full walkthroughs' and four game chips on a dark gradient with purple, green, orange, and blue accents and a small pipecode.ai attribution.

When you want hands-on reps immediately after reading, drill the SQL practice library →, rehearse on JOIN problems →, and stack the aggregation muscles with GROUP BY drills →.


On this page


1. Why gamified SQL works (and where it stops working)

Tutorial fatigue is real — narrative + branching state + visible progress is the only learning loop that survives the fourth GROUP BY exercise

The one-sentence invariant: a SQL learner who quits after the fourth GROUP BY HAVING exercise has not failed at SQL — they have failed at the learning loop that 90% of free tutorials use, which is "here is exercise N of 80, here is the model answer, click next." Gamified SQL rebuilds the loop with three ingredients borrowed from video-game design: a story (you are solving a murder, you are escaping an island), branching state (your last query opened the next clue), and a visible progress bar (4 of 8 quests cleared, 1 of 4 clues found). Once those three ingredients are there, the dopamine reward loop fires on every successful query — and the same student who quit at exercise 4 in a textbook will cheerfully write 30 queries in an evening to escape the island.

The four-part anatomy of a gamified SQL game.

  • Narrative wrapper. A story that gives every query a reason to be written — a clue to find, a quest to clear, a raft to build. Not "list the customers in city X." Instead: "the witness lives on the last house on Northwestern Drive — find them."
  • Branching state. The answer to query N becomes the seed for query N+1. You cannot skip ahead by reading a model solution because the next prompt depends on what you found. This is the single biggest UX upgrade over a static exercise list.
  • Visible progress. A clue board, a quest counter, a stamp that says "CASE SOLVED" at the end. The brain treats progress as a reward and writes the next query for free.
  • Honest difficulty curve. The early levels teach SELECT + WHERE in 90 seconds; the later levels chain three or four JOINs; the final level lifts the abstraction to GROUP BY + HAVING or to DML (INSERT / UPDATE / DELETE). Each level introduces one new keyword on top of everything taught so far.

What "gamified SQL" actually is — and is not.

  • It is a fully working SQL sandbox (SQLite, MySQL-flavoured, or Postgres) where every query you write executes against a real schema and the result drives the next narrative beat. Free, browser-based, no signup in most cases.
  • It is not a quiz that asks "which keyword does X?" and rewards a button click. The query has to actually run, return rows, and contain enough rows that the story logic can branch on it.
  • It is not an interactive video lecture. The game is playable; the lecture is watchable. The former requires output, the latter requires attention.
  • It is not a substitute for targeted interview practice once the basics are in muscle memory — that is where targeted libraries on the PipeCode practice catalogue take over.

The two breakout free games.

  • SQL Murder Mystery (Northwestern University's Knight Lab) — a one-mystery detective story set in fictional "SQL City" on January 15, 2018. About 2 to 3 hours end-to-end. Free, browser-based, runs in an embedded SQLite sandbox. Teaches SELECT, WHERE, LIKE, INNER JOIN, and chain joins across four to six tables. The canonical "give this to your bootcamp class for the first JOIN lesson" pick.
  • SQL Island — a desert-island narrative originally written in German for a university SQL course (HCI University of Applied Sciences Kaiserslautern). About 1 to 2 hours end-to-end. Free, browser-based. Teaches SELECT, WHERE, INNER JOIN, ORDER BY, LIMIT, GROUP BY, HAVING, INSERT, UPDATE, and DELETE — a broader keyword surface than Murder Mystery, with a softer curve for absolute beginners.

The honest ceiling.

  • Games teach the first 30% of SQL brilliantly. SELECT, WHERE, INNER JOIN, GROUP BY, HAVING, ORDER BY, LIMIT, LIKE, basic DML — every concept that fits naturally inside a narrative ("find the witness," "count the survivors") is exactly the concept gamified SQL gets right.
  • Games do not teach the next 70%. Window functions (ROW_NUMBER, LAG, LEAD, SUM OVER), CTEs and recursive CTEs, subqueries, EXPLAIN plans, indexing, NULL semantics in three-valued logic, OLAP set operations (UNION ALL, INTERSECT, EXCEPT), GROUPING SETS / ROLLUP / CUBE, JSON / array functions, and every "company-flavoured" interview pattern — none of these fit inside a story without becoming contrived puzzles.
  • The transition. Once a learner has cleared SQL Island and SQL Murder Mystery, the next 30 hours of practice belong to interview-style, problem-of-the-day libraries — which is where the PipeCode SQL drills and the SQL for data engineering interviews course take the baton.

Who this walkthrough is for.

  • The beginner stuck on tutorial 4. You wrote SELECT + WHERE + INNER JOIN three times each and the next exercise list looks identical. The two games below replace the list with a story, and you write 30 queries without noticing.
  • The bootcamp TA or university lecturer. You need a 1-hour lesson that introduces JOINs without losing the back half of the class. SQL Murder Mystery Steps 1 to 3 is the canonical answer.
  • The intermediate learner who hit a wall. You can write SELECT + JOIN + GROUP BY but freeze on window functions. The games will not unlock window functions, but they will sharpen JOIN intuition, and that intuition is what makes the next 70% learnable.
  • The interview-prep candidate two weeks out. You probably should not be playing games — you should be on PipeCode drilling company-tagged problems. But if you need a low-cognitive-load warmup, the games are 90 minutes well spent before a hard interview week.

The four games this post walks through end-to-end.

  • SQL Murder Mystery (Section 2) — 1 mystery, 2 to 3 hours, ~8 SQL queries, free, browser, US college / bootcamp staple.
  • SQL Island (Section 3) — 8 quests, narrative-driven, free, browser, originally German — great for absolute beginners.
  • Schemaverse (Section 4) — multiplayer space strategy game where every move is a Postgres query — harder learning curve, intermediate audience.
  • CodingGame SQL puzzles (Section 4) — bite-sized targeted SQL puzzles wrapped in the CodingGame UI, MySQL flavour, progress tracking.

Plus an honourable mention for Lost at SQL, a physical card game for classroom / team activities — covered briefly in Section 4 as the "offline" complement to the four browser games.

What interviewers listen for when a candidate says "I learned SQL with games."

  • Do you recognise that the games teach WHERE + JOIN + GROUP BY brilliantly but do not teach window functions, CTEs, NULL semantics? — senior signal that you know your tools.
  • Do you treat games as a warmup for a real practice library, not as the destination? — required answer.
  • Do you remember which game taught which concept (Murder Mystery → chain JOIN; SQL Island → GROUP BY / HAVING)? — senior signal.
  • Do you mention pairing games with a real dataset (Kaggle / NYC taxi / Stack Overflow dump) to bridge the toy-schema-to-production gap? — senior signal.

Worked example — the tutorial-fatigue diagnostic

Detailed explanation. Before recommending a game, diagnose where the learner actually stalled. A learner who quit at SELECT does not need a chain-JOIN mystery; a learner who can write three-table joins but blanks on GROUP BY HAVING does not need SQL Island Quest 1. The fastest diagnostic is to ask three short questions and read the answers in order.

Question. Build a 3-question diagnostic that maps a learner's stall point to one of the four gamified-SQL entry points: SQL Island Q1 (absolute beginner), Murder Mystery Step 1 (knows SELECT, weak on JOIN), SQL Island Q5 (knows JOIN, weak on GROUP BY), CodingGame SQL puzzles (knows the basics, wants targeted drills).

Input.

Q Question Answer A Answer B
1 Can you write SELECT col FROM t WHERE col = 'x' from memory? yes no
2 Can you JOIN two tables on a foreign key without looking it up? yes no
3 Can you write GROUP BY ... HAVING COUNT(*) > N without help? yes no

Code.

-- A pseudo-SQL "diagnostic" expressed as a CASE chain
SELECT
    learner_id,
    CASE
        WHEN q1 = 'no'                              THEN 'start with SQL Island Quest 1'
        WHEN q1 = 'yes' AND q2 = 'no'               THEN 'start with SQL Murder Mystery Step 1'
        WHEN q1 = 'yes' AND q2 = 'yes' AND q3 = 'no' THEN 'start with SQL Island Quest 5'
        WHEN q1 = 'yes' AND q2 = 'yes' AND q3 = 'yes' THEN 'graduate to CodingGame SQL puzzles + PipeCode'
        ELSE 'ask one more diagnostic'
    END AS recommended_entry_point
FROM learner_diagnostic;
Enter fullscreen mode Exit fullscreen mode

Step-by-step explanation.

  1. Q1 isolates the SELECT/WHERE primitive. A "no" means the learner has never executed a query against a sandbox — start with SQL Island Quest 1, which teaches that primitive inside 90 seconds.
  2. Q2 isolates JOIN. A "yes" on Q1 with a "no" on Q2 means the learner needs the chain-JOIN drill — Murder Mystery is purpose-built for it.
  3. Q3 isolates GROUP BY HAVING. A "yes" on Q1+Q2 with "no" on Q3 means the learner needs an aggregation context — SQL Island Quests 5 and 6 introduce GROUP BY + HAVING inside a story.
  4. A "yes" on all three means games are no longer the bottleneck — graduate to targeted drills (CodingGame SQL puzzles) and interview-style problem libraries (PipeCode).
  5. The CASE expression is a searched CASE (predicates per branch), not a simple CASE — the only safe pattern when any of the answers could be NULL or 'unsure'.

Output.

learner_id q1 q2 q3 recommended_entry_point
1 no no no start with SQL Island Quest 1
2 yes no no start with SQL Murder Mystery Step 1
3 yes yes no start with SQL Island Quest 5
4 yes yes yes graduate to CodingGame SQL puzzles + PipeCode

Rule of thumb. Never recommend "play SQL Island then play Murder Mystery" as a one-size answer. Diagnose the stall point first — the game that fits the stall is the game the learner will finish.

Worked example — the reward-loop budget per learner

Detailed explanation. Gamified SQL works only as long as the dopamine reward fires reliably. Empirically, a learner sustains attention through about 8 to 12 successful queries in a session before the loop weakens and the next query starts to feel like work. A game that fits inside one session has to deliver its "case solved" payoff within that budget; a game that needs three sessions has to give a meaningful "level cleared" payoff at the end of each session.

Question. Given a learner with a 90-minute single-session attention budget and an estimated 8-minute average per query (write + run + interpret), how many queries can they realistically complete in one sitting — and which of the four games fits that budget?

Input.

Game Total queries Avg time per query (min) Total time (min)
SQL Murder Mystery 8 15 120
SQL Island 12 7 84
CodingGame SQL (intro) 10 6 60
Schemaverse (first round) 20 10 200

Code.

-- Treat each game as a row; compute "fits in one 90-min session?"
SELECT
    game,
    total_queries,
    avg_minutes_per_query,
    total_queries * avg_minutes_per_query AS total_minutes,
    CASE
        WHEN total_queries * avg_minutes_per_query <= 90 THEN 'one session'
        WHEN total_queries * avg_minutes_per_query <= 180 THEN 'two sessions'
        ELSE 'multi-session'
    END AS session_budget
FROM gamified_sql_games
ORDER BY total_minutes ASC;
Enter fullscreen mode Exit fullscreen mode

Step-by-step explanation.

  1. Multiply rows out per game: SQL Island = 12 × 7 = 84 minutes; CodingGame intro = 10 × 6 = 60; Murder Mystery = 8 × 15 = 120; Schemaverse first round = 20 × 10 = 200.
  2. The CASE chain buckets each game into "one session" (≤90 minutes), "two sessions" (≤180 minutes), or "multi-session" (>180 minutes).
  3. Sort ascending — the fastest game to a "case solved" payoff is on top, which is the right order for recommending to a tutorial-fatigued learner who needs an early win.
  4. SQL Island and CodingGame fit one session; Murder Mystery is a "two sessions" game for most learners; Schemaverse is multi-session and should be reserved for learners who are already comfortable with the basics.

Output.

game total_queries avg_minutes_per_query total_minutes session_budget
CodingGame SQL (intro) 10 6 60 one session
SQL Island 12 7 84 one session
SQL Murder Mystery 8 15 120 two sessions
Schemaverse (first round) 20 10 200 multi-session

Rule of thumb. Always check the learner's session budget before recommending a game. A two-hour Murder Mystery handed to a learner with a 45-minute attention window will be abandoned at the chain-JOIN step — exactly the same failure mode as a textbook.

SQL interview question on choosing a learning loop

A senior interviewer might frame this as: "You inherit a 12-learner bootcamp cohort where half quit after the first JOIN lesson. Design a 7-day relearning plan using free SQL games, then graduate them to PipeCode for window functions and CTE drills."

Solution Using a 7-day staged plan (SQL Island → Murder Mystery → PipeCode)

-- Day-by-day curriculum as a single rowset
SELECT day,
       activity,
       primary_concept,
       expected_queries,
       success_check
FROM (VALUES
    (1, 'SQL Island Quests 1-4',                'SELECT + WHERE + INNER JOIN',     16, 'Quest 4 cleared'),
    (2, 'SQL Island Quests 5-8',                'GROUP BY + HAVING + DML',         18, 'Escape raft built'),
    (3, 'SQL Murder Mystery Steps 1-3',         'Chain JOIN across 3 tables',      10, 'Suspect identified'),
    (4, 'SQL Murder Mystery Bonus round',       'Compound WHERE + multi-table',     8, 'Killer identified'),
    (5, 'CodingGame SQL puzzles (10 easy)',     'Targeted aggregation + JOIN',     10, '10 puzzles green'),
    (6, 'PipeCode JOIN + GROUP BY drills',      'Interview-style problem solving', 12, 'PipeCode dashboard ≥ 60%'),
    (7, 'PipeCode window function drills',      'ROW_NUMBER, LAG, SUM OVER',        8, 'Window section cleared')
) AS plan(day, activity, primary_concept, expected_queries, success_check)
ORDER BY day;
Enter fullscreen mode Exit fullscreen mode

Step-by-step trace.

Day Activity Primary concept Queries Success check
1 SQL Island Quests 1-4 SELECT + WHERE + INNER JOIN 16 Quest 4 cleared
2 SQL Island Quests 5-8 GROUP BY + HAVING + DML 18 Escape raft built
3 SQL Murder Mystery Steps 1-3 Chain JOIN across 3 tables 10 Suspect identified
4 SQL Murder Mystery Bonus round Compound WHERE + multi-table 8 Killer identified
5 CodingGame SQL puzzles (10 easy) Targeted aggregation + JOIN 10 10 puzzles green
6 PipeCode JOIN + GROUP BY drills Interview-style problem solving 12 PipeCode dashboard ≥ 60%
7 PipeCode window function drills ROW_NUMBER, LAG, SUM OVER 8 Window section cleared

The plan front-loads the highest-narrative-pull game (SQL Island) on Day 1 because the lift-off matters most after a quit. Murder Mystery enters on Day 3 once the cohort has 30 queries under their belt and can survive the chain-JOIN spike. PipeCode enters Days 6 and 7 to bridge to window functions — the one concept no game teaches.

Output:

day activity primary_concept
1 SQL Island Quests 1-4 SELECT + WHERE + INNER JOIN
2 SQL Island Quests 5-8 GROUP BY + HAVING + DML
3 SQL Murder Mystery Steps 1-3 Chain JOIN across 3 tables
4 SQL Murder Mystery Bonus round Compound WHERE + multi-table
5 CodingGame SQL puzzles (10 easy) Targeted aggregation + JOIN
6 PipeCode JOIN + GROUP BY drills Interview-style problem solving
7 PipeCode window function drills ROW_NUMBER, LAG, SUM OVER

Why this works — concept by concept:

  • Reward-loop first — Day 1 is SQL Island because it ships an early win (Quest 1 clears in under 5 minutes). A learner who quit after a JOIN lesson needs a fast dopamine hit, not another JOIN.
  • Curve before mass — Days 1 to 2 keep the keyword surface narrow (SELECT, WHERE, JOIN). Days 3 to 4 add chain JOINs (Murder Mystery). Days 5 to 7 broaden to targeted drills and finally window functions. Each day adds at most one new big idea.
  • Game-to-library handoff — CodingGame on Day 5 is the bridge: still gamified UI, but the problems are interview-flavoured rather than story-flavoured. It softens the transition into PipeCode.
  • PipeCode for window functions — no game teaches ROW_NUMBER / LAG / LEAD properly because they need real-world datasets and analyst intent. Day 7 is the only honest path to those.
  • Success checks are concrete — each day has a verifiable end-state ("Quest 4 cleared", "PipeCode dashboard ≥ 60%"). A learner who cannot point to the success check did not finish the day, and the TA should not advance them.
  • Cost — about 6 to 8 hours of focused learner time across 7 days. No paid tools; PipeCode has a free tier for the drill phases.

SQL
Topic — SQL
SQL practice library (SQL)

Practice →


2. SQL Murder Mystery — full walkthrough

A four-clue chain JOIN dressed as a detective story — the gold-standard first lesson in multi-table SQL

The mental model in one line: SQL Murder Mystery teaches you that a real-world SQL question is not one query — it is a chain of queries where each result narrows the next predicate, and the only way through the chain is INNER JOIN with the right ON predicate. Once you can quote that sentence, every "I can write SELECT but I cannot connect tables" learner has a 2-hour fix.

Visual SQL Murder Mystery walkthrough — a mystery board with 4 numbered clue cards linked by arrows (crime scene report → witness interview → fitness check-ins → killer ID + bonus round), each card shows the relevant table and the SQL concept used; on a light PipeCode card.

The premise in one paragraph. A murder occurred in SQL City on January 15, 2018. You are the detective. The local police have given you read access to their entire SQLite database — eight tables connecting people, driver's licenses, gym memberships, gym check-ins, interview transcripts, income records, Facebook event check-ins, and crime scene reports. Your job is to write the SQL queries that walk from the initial police report all the way to the killer. The game runs in an embedded browser sandbox at mystery.knightlab.com — no signup, no install, no paid tier.

The schema you have to learn first.

  • crime_scene_report(date, type, description, city). The starting point. Filter for type = 'murder', city = 'SQL City', and the date of the crime to get two witness mentions in the description.
  • person(id, name, license_id, address_number, address_street_name, ssn). The master person table. Every other person-related lookup joins back here.
  • drivers_license(id, age, height, eye_color, hair_color, gender, plate_number, car_make, car_model). Cross-reference with witness statements that mention hair colour, height, or a partial license plate.
  • interview(person_id, transcript). Witness statements. Each witness has a transcript that contains a clue about the killer — gym membership ID prefix, hair colour, height, or a Facebook event clue.
  • get_fit_now_member(id, person_id, name, membership_start_date, membership_status). The fitness club records. One witness statement narrows the suspect to a member of "Get Fit Now Gym" with a specific membership ID prefix.
  • get_fit_now_check_in(membership_id, check_in_date, check_in_time, check_out_time). Gym attendance log. Cross with get_fit_now_member to identify who was at the gym on the relevant date.
  • income(ssn, annual_income). Used in the bonus round to identify a wealthy accomplice.
  • facebook_event_checkin(person_id, event_id, event_name, date). Used in the bonus round to confirm an attendance at "SQL Symphony Concert" three times in December 2017.

The four-clue progression.

  • Clue 1 — the crime scene report. Filter by date, city, and crime type. Two witnesses are mentioned in the description.
  • Clue 2 — interview the witnesses. JOIN personinterview on the witness names from Clue 1. Read the transcripts.
  • Clue 3 — the gym alibi chain. JOIN get_fit_now_check_inget_fit_now_memberdrivers_license (via person) to narrow gym members who match the witness descriptions.
  • Clue 4 — the killer and the bonus round. A single suspect remains. The bonus round uses interview (the killer's transcript), facebook_event_checkin, and income to identify the person who hired the killer.

What Murder Mystery teaches you cold.

  • SELECT + WHERE + LIKE. The opening filter on crime_scene_report introduces pattern matching (description LIKE '%witness%' style probes).
  • INNER JOIN on a foreign key. The witness lookup teaches the canonical JOIN ... ON a.person_id = b.id shape.
  • Chain JOIN across 3+ tables. The gym alibi clue requires check_in JOIN member JOIN person JOIN drivers_license — exactly the chain-JOIN drill most beginners miss.
  • Compound WHERE. The bonus round forces predicates like event_name = 'SQL Symphony Concert' AND date BETWEEN '2017-12-01' AND '2017-12-31' to filter to three attendances.
  • Multi-table reasoning. The biggest skill unlock — holding two or three intermediate results in your head while you compose the next query. This is the single biggest predictor of "can write production analytics SQL."

What it intentionally skips.

  • Window functions (no ROW_NUMBER, no LAG / LEAD, no SUM OVER).
  • GROUP BY drills. A single COUNT might appear but the game does not lean on aggregation.
  • CTEs and subqueries. Solutions are written as flat JOIN chains; the game never asks for a WITH ... AS block.
  • NULL semantics. The schema is mostly clean — you can play the whole game without confronting three-valued logic.

Common interview probes about Murder Mystery.

  • "Walk me through how you'd solve Step 3" — interviewers want the chain-JOIN shape narrated, not memorised.
  • "Where would you use a CTE if you re-wrote it for production?" — senior signal that you can lift gamified shapes to dbt patterns.
  • "What does Murder Mystery not teach?" — the right answer is "window functions, CTEs, and NULL handling."

Worked example — Step 1: pull the crime scene report

Detailed explanation. The mystery's opening prompt tells you a murder happened in SQL City on January 15, 2018. The first query has to filter the crime_scene_report table on three predicates: type, city, and date. The result is one row whose description column names the two witnesses by gym membership and home address — that one row is the seed of the entire investigation.

Question. Write the opening query that retrieves the murder report from crime_scene_report for the date 2018-01-15 in SQL City, and identify the two witnesses mentioned in the description.

Input.

date type description city
20180115 murder "Witness #1 lives at last house on Northwestern Dr. Witness #2 is member of Get Fit Now Gym (ID GE3JL)." SQL City
20180115 robbery "Suspect fled south on Maple." SQL City
20180110 murder "..." Albany

Code.

SELECT date, type, description, city
FROM crime_scene_report
WHERE type = 'murder'
  AND city = 'SQL City'
  AND date = 20180115;
Enter fullscreen mode Exit fullscreen mode

Step-by-step explanation.

  1. The WHERE type = 'murder' filter immediately drops the robbery and any unrelated crime types.
  2. The AND city = 'SQL City' filter drops every report from other cities — the schema stores date as an integer in YYYYMMDD form, which is one of the small surprises the mystery throws at you.
  3. The AND date = 20180115 filter narrows to the one row about the murder.
  4. The single returned row's description column names two witnesses by attributes (one lives at the last house on Northwestern Drive; the other is a Get Fit Now Gym member with ID prefix GE3JL) — not by name. The next query has to translate those attributes into person IDs.

Output.

date type description city
20180115 murder "Witness #1 lives at last house on Northwestern Dr. Witness #2 is member of Get Fit Now Gym (ID GE3JL)." SQL City

Rule of thumb. The mystery never gives you a name directly — it gives you a predicate. Every query in the chain has to translate a predicate into a person ID via the appropriate JOIN. That translation step is the entire skill being trained.

Worked example — Step 2: identify the two witnesses

Detailed explanation. The description from Step 1 names a Northwestern Drive resident and a Get Fit Now Gym member. Two parallel queries identify each: one filters person by address (with a clever MAX trick to find the last house on the street), the other filters get_fit_now_member by membership ID prefix.

Question. Find the person.id of Witness #1 (last house on Northwestern Drive) and Witness #2 (Get Fit Now Gym member with ID starting GE3JL). Then read both witnesses' interview transcripts.

Input — person.

id name address_number address_street_name
14887 Morty Schapiro 4919 Northwestern Dr
16371 Annabel Miller 103 Franklin Ave
19831 Jeremy Bowers 530 Washington Pl

Input — get_fit_now_member.

id person_id name
GE3JL2 16371 Annabel Miller
AB1CD3 19831 Jeremy Bowers

Code.

-- Witness 1 — last house on Northwestern Dr
SELECT id, name
FROM person
WHERE address_street_name = 'Northwestern Dr'
  AND address_number = (
      SELECT MAX(address_number)
      FROM person
      WHERE address_street_name = 'Northwestern Dr'
  );

-- Witness 2 — Get Fit Now member with ID starting GE3JL
SELECT m.person_id, m.name
FROM get_fit_now_member m
WHERE m.id LIKE 'GE3JL%';

-- Read both transcripts
SELECT p.name, i.transcript
FROM interview i
JOIN person p ON p.id = i.person_id
WHERE p.id IN (14887, 16371);
Enter fullscreen mode Exit fullscreen mode

Step-by-step explanation.

  1. The "last house" clue is the address with the maximum address_number on Northwestern Drive. A correlated MAX subquery is the cleanest way to express it.
  2. The Get Fit Now Gym clue uses LIKE 'GE3JL%' — the wildcard % matches anything after the prefix. This is the mystery's introduction to pattern matching.
  3. Both witnesses are now identified by person.id (14887 and 16371). Joining interview on person.id retrieves both transcripts in a single query.
  4. The transcripts narrow the suspect further: one transcript names a tall man with a "Get Fit Now" gold-tier membership who left the gym on January 9; the other names a hair colour and a partial plate.

Output.

id name transcript_summary
14887 Morty Schapiro "Saw man with gold membership leaving gym Jan 9 around 7 PM"
16371 Annabel Miller "Tall man, partial plate H42W0X, was at gym that day"

Rule of thumb. Read the transcript literally. Every concrete noun (gym, gold tier, January 9, partial plate H42W0X) is a predicate for a future WHERE clause. Highlight them as you read.

Worked example — Step 3: the gym alibi chain JOIN

Detailed explanation. The witness statements name a Get Fit Now member who checked in around January 9 with a "gold" membership and a partial plate H42W0X. To find that person you have to join three tables in one query: get_fit_now_check_in (the attendance log) → get_fit_now_member (to find membership tier and person link) → drivers_license via person (to match the partial plate). This is the canonical chain JOIN drill.

Question. Find every Get Fit Now member who (a) has a gold membership, (b) checked in on January 9, 2018, and (c) has a license plate containing H42W0X.

Input — get_fit_now_check_in.

membership_id check_in_date check_in_time
48Z7A 20180109 1600
48Z55 20180109 1530

Input — get_fit_now_member.

id person_id name membership_status
48Z7A 67318 Jeremy Bowers gold
48Z55 70912 Random Member silver

Input — drivers_license + person link.

person_id plate_number license.car_model
67318 H42W0X Honda Civic
70912 RR4321 Ford F150

Code.

SELECT p.id, p.name, dl.plate_number, m.membership_status
FROM get_fit_now_check_in c
JOIN get_fit_now_member m
       ON m.id = c.membership_id
JOIN person p
       ON p.id = m.person_id
JOIN drivers_license dl
       ON dl.id = p.license_id
WHERE c.check_in_date = 20180109
  AND m.membership_status = 'gold'
  AND dl.plate_number LIKE '%H42W0X%';
Enter fullscreen mode Exit fullscreen mode

Step-by-step explanation.

  1. Start at get_fit_now_check_in c — the log row drives the predicate check_in_date = 20180109.
  2. JOIN get_fit_now_member m on the membership ID — this gives you the membership tier (gold) and the link to a person.
  3. JOIN person p on the member's person_id — this gives you the name and the link to drivers_license via p.license_id.
  4. JOIN drivers_license dl on p.license_id — this gives you the plate to check against the witness's partial.
  5. The compound WHERE narrows on three independent conditions: date of check-in, membership tier, and plate match. The LIKE '%H42W0X%' is the pattern-matching trick taught here.
  6. The result is a single row: Jeremy Bowers (person.id = 67318) — the prime suspect.

Output.

id name plate_number membership_status
67318 Jeremy Bowers H42W0X gold

Rule of thumb. When the mystery (or any real interview question) gives you three conditions, write them as three predicates on the innermost WHERE — not as nested subqueries. The chain JOIN is the canonical shape; subqueries are a refactor, not a starting point.

Worked example — Step 4: the bonus round (who hired the killer)

Detailed explanation. Solving the case correctly unlocks a bonus prompt: "The killer says they were hired by a wealthy woman who attended the SQL Symphony Concert three times in December 2017. Find her." This forces a second chain of JOINs across interview (the killer's confession), facebook_event_checkin (the three attendances), person (to look up gender), and income (to filter to "wealthy").

Question. Find the person.id of the wealthy woman who attended the SQL Symphony Concert exactly three times in December 2017.

Input — facebook_event_checkin.

person_id event_name date
99716 SQL Symphony Concert 20171206
99716 SQL Symphony Concert 20171212
99716 SQL Symphony Concert 20171229
50000 SQL Symphony Concert 20171205

Input — income.

ssn annual_income
987654321 1200000
111223333 45000

Input — person + drivers_license link.

person.id name ssn dl.gender
99716 Miranda Priestly 987654321 female
50000 Other Person 111223333 male

Code.

SELECT p.id, p.name, i.annual_income
FROM facebook_event_checkin fb
JOIN person p           ON p.id = fb.person_id
JOIN drivers_license dl ON dl.id = p.license_id
JOIN income i           ON i.ssn = p.ssn
WHERE fb.event_name = 'SQL Symphony Concert'
  AND fb.date BETWEEN 20171201 AND 20171231
  AND dl.gender = 'female'
GROUP BY p.id, p.name, i.annual_income
HAVING COUNT(*) = 3
ORDER BY i.annual_income DESC
LIMIT 1;
Enter fullscreen mode Exit fullscreen mode

Step-by-step explanation.

  1. Start at facebook_event_checkin fb and filter on event_name and the December 2017 date range.
  2. JOIN person p on the check-in's person_id — gives you the name and the links forward.
  3. JOIN drivers_license dl on p.license_id — needed to filter on gender = 'female'.
  4. JOIN income i on p.ssn — gives the annual income for the "wealthy" filter.
  5. GROUP BY the person's identity columns so that COUNT(*) counts each attendance per person.
  6. HAVING COUNT(*) = 3 keeps only people who attended exactly three times — the precise condition the killer mentioned.
  7. ORDER BY income descending and LIMIT 1 picks the wealthiest qualifying woman — Miranda Priestly in the canonical solution.

Output.

id name annual_income
99716 Miranda Priestly 1200000

Rule of thumb. The bonus round is the first time the mystery asks you to combine JOIN + GROUP BY + HAVING in one query — the exact shape that will appear in 60% of senior SQL interviews. Recognise it; rehearse it; keep the shape in muscle memory.

SQL interview question on chain JOIN reasoning

A senior interviewer often opens with: "You have an event check-in table, a member table, a person table, and a license table. Find every person who checked into a specific event exactly N times in a date range with a specific demographic attribute. Walk me through your JOIN order and predicate placement."

Solution Using a four-table chain JOIN with HAVING COUNT

SELECT p.id,
       p.name,
       COUNT(*) AS visits
FROM facebook_event_checkin fb
JOIN person p           ON p.id = fb.person_id
JOIN drivers_license dl ON dl.id = p.license_id
WHERE fb.event_name = 'SQL Symphony Concert'
  AND fb.date BETWEEN 20171201 AND 20171231
  AND dl.gender = 'female'
GROUP BY p.id, p.name
HAVING COUNT(*) = 3;
Enter fullscreen mode Exit fullscreen mode

Step-by-step trace.

fb.person_id event_name date dl.gender counts?
99716 SQL Symphony Concert 20171206 female yes
99716 SQL Symphony Concert 20171212 female yes
99716 SQL Symphony Concert 20171229 female yes
50000 SQL Symphony Concert 20171205 male filtered out

Three matching rows survive the WHERE for person.id = 99716. The GROUP BY collapses them into one group and COUNT(*) = 3 keeps the group; HAVING applies after aggregation, which is the right place for a count-based filter.

Output:

id name visits
99716 Miranda Priestly 3

Why this works — concept by concept:

  • Chain JOIN reads top-down — start at the driving table whose predicate is the narrowest (the event check-in date range); each subsequent JOIN adds one filter or one displayed column. The order matches the way you'd narrate the question to a colleague.
  • Predicate placement: WHERE vs ON vs HAVING — the date and gender filters go in WHERE because they are row-level predicates against the raw join. The COUNT(*) = 3 filter goes in HAVING because it operates on the aggregate, which only exists after GROUP BY.
  • GROUP BY the identity columnsp.id, p.name is the right key because name is functionally dependent on id. Some dialects require both in GROUP BY; modern engines allow GROUP BY p.id and infer the rest.
  • HAVING vs WHERE — the order of operations — SQL evaluates FROM → JOIN → WHERE → GROUP BY → HAVING → SELECT → ORDER BY → LIMIT. Filters that depend on aggregates must go in HAVING, never WHERE.
  • Cost — O(check-in × matched persons) for the hash join; the aggregate is O(rows) over the joined output. The COUNT-based HAVING is cheap once the groups are built.

SQL
Topic — joins
JOIN problems (SQL)

Practice →


3. SQL Island — full walkthrough

Eight quests, one escape raft — the gentlest on-ramp to GROUP BY, HAVING, and basic DML

The mental model in one line: SQL Island teaches you that a SQL keyword is just a verb in a story — SELECT means "look", JOIN means "introduce two characters", GROUP BY means "count the people in each village" — and once each keyword has a narrative role, learners write 30 queries in an evening without noticing it is "work". Where Murder Mystery is a single-arc detective drama, SQL Island is a side-quest-driven adventure that introduces one new SQL keyword per quest.

Visual SQL Island walkthrough — an island map with 8 numbered quest pins along a path from crash site to escape raft, each pin shows the quest, the table involved, and the SQL skill unlocked; on a light PipeCode card.

The premise. A plane crashes and you wake up on a small tropical island populated by a few villages of friendly inhabitants, hostile inhabitants, and a few craftsmen. To escape, you must clear eight quests — each quest forces you to write one or two SQL queries against the island's small relational schema. The game runs in a free browser sandbox at sql-island.informatik.uni-kl.de (originally a teaching tool from HCI University of Applied Sciences Kaiserslautern). No signup required; the SQL dialect is MySQL-flavoured.

The schema.

  • inhabitants(id, name, village_id, gender, status, weapon_id, gold). The master person table. status is friendly, hostile, or dead.
  • items(id, name, type, price, owner_id). Everything you can pick up: weapons, food, tools, raft parts.
  • weapons(id, name, strength). Cross-reference with inhabitants.weapon_id to identify who carries what.
  • friends(person_a_id, person_b_id). A small friendship graph used in later quests.

The eight quests in order.

  • Quest 1 — find a friendly inhabitant. Simple WHERE on inhabitants where status = 'friendly'. The "first SELECT" lesson.
  • Quest 2 — locate food. INNER JOIN inhabitants × items to find who is carrying food. First JOIN lesson.
  • Quest 3 — find weapons. JOIN with a filter (items.type = 'weapon'). Reinforces JOIN + WHERE pairing.
  • Quest 4 — find a craftsman, ordering items by price. ORDER BY + LIMIT to find the cheapest craftsman whose type = 'craftsman'.
  • Quest 5 — count survivors per village. GROUP BY village_id with COUNT(*).
  • Quest 6 — find the strongest village. GROUP BY + HAVING with a max-strength aggregate.
  • Quest 7 — gather raft parts. INSERT INTO items to add raft components.
  • Quest 8 — escape. UPDATE / DELETE to mark the player's status as escaped and remove no-longer-needed inventory.

What SQL Island teaches you cold.

  • SELECT + WHERE on a single table. Quest 1's "find friendly inhabitants" is a one-line WHERE filter.
  • INNER JOIN on a foreign key. Quests 2 and 3 introduce the canonical join shape.
  • JOIN with multi-table filter. Quest 4 chains JOIN with ORDER BY + LIMIT — the "top N" pattern.
  • GROUP BY with COUNT(*). Quest 5 is the cleanest first GROUP BY lesson in the gamified catalogue.
  • HAVING + aggregate. Quest 6 teaches HAVING in a narrative ("the strongest village"), which is exactly when most beginners finally understand the difference between WHERE and HAVING.
  • Basic DML. Quests 7 and 8 finally let the player write (INSERT, UPDATE, DELETE) — most tutorials skip this entirely.

What it skips.

  • Window functions. Not a hint of ROW_NUMBER, LAG, or SUM OVER.
  • CTEs. Solutions stay as flat single-statement queries.
  • Subqueries. The island has one or two natural correlated subquery shapes (e.g. "strongest village") but the canonical solutions use HAVING instead.
  • Complex NULL semantics. The island's schema is mostly NULL-free; you can finish without confronting the IS NULL trap.

The German angle. The original game is in German (the "Vorsicht!" / "willkommen" prompts). An English mirror exists and is widely used in US bootcamps. The German UX is a fun side benefit — playing it bilingually doubles the keyword reinforcement.

Common interview probes about SQL Island.

  • "Which quest first introduces GROUP BY?" — Quest 5 (count survivors per village).
  • "Why does the island teach DML when Murder Mystery does not?" — because escape requires writing changes, which forces INSERT / UPDATE / DELETE into the story arc.
  • "What is the right SQL Island → Murder Mystery sequence?" — SQL Island first (broader keyword surface, gentler curve), Murder Mystery second (deeper chain-JOIN drill).

Worked example — Quest 1: find a friendly inhabitant

Detailed explanation. Quest 1's prompt: "you wake up on the island and need someone to help — find any friendly inhabitant." This is the absolute-beginner gate — one filter on one column. If a learner cannot pass Quest 1 in under 5 minutes, the game has perfectly diagnosed their stall (no prior SQL exposure at all) and the right intervention is a 10-minute SELECT + WHERE refresher.

Question. Write the query that retrieves every inhabitant whose status is friendly. Return at least name and village.

Input.

id name village_id status
1 Kim 1 friendly
2 Frank 1 hostile
3 Mary 2 friendly
4 Ben 2 dead

Code.

SELECT id, name, village_id, status
FROM inhabitants
WHERE status = 'friendly';
Enter fullscreen mode Exit fullscreen mode

Step-by-step explanation.

  1. FROM inhabitants scans the master person table.
  2. WHERE status = 'friendly' keeps only the rows whose status is exactly the string 'friendly'. SQL is case-sensitive for string comparisons in most dialects when collation is binary; the game uses a case-insensitive collation by default, so 'Friendly' and 'friendly' both match.
  3. SELECT id, name, village_id, status returns the columns the player needs to choose a target. Choosing id = 1 (Kim) advances the story.
  4. The single-table filter is the only SQL primitive being trained here — no JOIN, no aggregate, no ordering.

Output.

id name village_id status
1 Kim 1 friendly
3 Mary 2 friendly

Rule of thumb. Quest 1 is the smallest possible SQL query. Treat it as a "tools work" smoke test — if a learner cannot return at least one row here, do not advance them to JOINs.

Worked example — Quest 2: locate food via JOIN

Detailed explanation. Quest 2's prompt: "you are hungry — find someone who is carrying food." This is the first JOIN lesson in the catalogue. The food is in the items table (type = 'food'); the carriers are in the inhabitants table. Joining them on items.owner_id = inhabitants.id returns each food carrier and the item they hold.

Question. Find every friendly inhabitant who is carrying an item of type food. Return the inhabitant's name and the food item's name.

Input — inhabitants.

id name status
1 Kim friendly
3 Mary friendly
5 Hostile Hank hostile

Input — items.

id name type owner_id
7 apple food 1
8 sword weapon 5
9 banana food 3

Code.

SELECT i.name AS carrier, it.name AS food
FROM inhabitants i
JOIN items it ON it.owner_id = i.id
WHERE it.type = 'food'
  AND i.status = 'friendly';
Enter fullscreen mode Exit fullscreen mode

Step-by-step explanation.

  1. The driving table is inhabitants i; the JOIN brings in items it where the item's owner_id matches the inhabitant's id.
  2. WHERE it.type = 'food' is a post-join filter — it discards every joined row where the item is not food. Equivalent to placing it in the ON clause for an INNER JOIN (semantically identical), but placing it in WHERE is the canonical SQL Island form.
  3. AND i.status = 'friendly' discards Hostile Hank — you do not want to steal food from a hostile.
  4. The two output columns rename the inhabitant's name as carrier and the item's name as food — small ergonomic touch that the game encourages.

Output.

carrier food
Kim apple
Mary banana

Rule of thumb. The first JOIN learners write should be INNER JOIN ... ON foreign_key = primary_key. Keep the relationship one-to-many and the predicate single-column. Save many-to-many bridge tables and composite keys for later quests.

Worked example — Quest 4: find the cheapest craftsman with ORDER BY + LIMIT

Detailed explanation. Quest 4's prompt: "you need a craftsman to build the raft — find the cheapest one." The items table has a price column (the gold cost of hiring the craftsman to build something). ORDER BY ascending price with LIMIT 1 returns exactly one row — the cheapest craftsman. This is the gamified introduction to the "top-N" pattern that dominates production analytics.

Question. Find the cheapest item of type craftsman and return the craftsman's name and price.

Input — items.

id name type price
12 Bob the Builder craftsman 50
13 Mary the Carpenter craftsman 30
14 Ed the Welder craftsman 100
15 bronze sword weapon 25

Code.

SELECT name, price
FROM items
WHERE type = 'craftsman'
ORDER BY price ASC
LIMIT 1;
Enter fullscreen mode Exit fullscreen mode

Step-by-step explanation.

  1. WHERE type = 'craftsman' narrows to the three craftsman rows — the weapon row is discarded.
  2. ORDER BY price ASC sorts ascending by price: Mary (30), Bob (50), Ed (100).
  3. LIMIT 1 keeps the first row only. Result is Mary the Carpenter, 30.
  4. The order of operations matters: WHERE → ORDER BY → LIMIT. Reversing them would either error or return wrong results — placing LIMIT before ORDER BY is not legal SQL syntax.

Output.

name price
Mary the Carpenter 30

Rule of thumb. ORDER BY + LIMIT is the canonical "top-N" pattern. It is also the pattern you will refactor to a window function (ROW_NUMBER() OVER (PARTITION BY ... ORDER BY ...)) the moment you need top-N per group — that refactor is where the game's keyword surface stops and PipeCode's begins.

Worked example — Quest 5: count survivors per village with GROUP BY

Detailed explanation. Quest 5's prompt: "to decide which village to escape to, count how many survivors live in each." A survivor is an inhabitant whose status is not dead. GROUP BY village_id partitions the rows into one group per village; COUNT(*) returns the number of rows in each. This is the introduction to aggregation in the gamified catalogue.

Question. Count the number of surviving (not dead) inhabitants per village and order the result with the largest village first.

Input — inhabitants.

id village_id status
1 1 friendly
2 1 hostile
3 2 friendly
4 2 dead
5 2 friendly
6 3 friendly

Code.

SELECT village_id, COUNT(*) AS survivors
FROM inhabitants
WHERE status != 'dead'
GROUP BY village_id
ORDER BY survivors DESC;
Enter fullscreen mode Exit fullscreen mode

Step-by-step explanation.

  1. WHERE status != 'dead' removes dead inhabitants before the GROUP BY — this is the right placement because it is a row-level filter.
  2. GROUP BY village_id partitions the surviving rows into three groups: village 1 (Kim + Frank → 2), village 2 (Mary + Survivor #5 → 2), village 3 (Inhab 6 → 1).
  3. COUNT(*) returns the size of each group. Note that COUNT(*) counts every row in the group; if the filter were placed in HAVING instead of WHERE, the dead inhabitants would have been counted (then dropped) — a subtle but expensive mistake.
  4. ORDER BY survivors DESC puts the largest village first. Ties are broken by village_id ASC by default in most dialects.

Output.

village_id survivors
1 2
2 2
3 1

Rule of thumb. Filter row-level predicates in WHERE; filter aggregate predicates in HAVING. Putting WHERE status != 'dead' in HAVING would still work because COUNT ignores the column directly, but the planner does extra work counting then discarding. WHERE first, HAVING after — the SQL execution order makes this rule free of risk.

Worked example — Quest 6: strongest village with HAVING

Detailed explanation. Quest 6's prompt: "you must avoid the strongest village — find which village has the highest average weapon strength." This requires joining inhabitants to weapons (via weapon_id), grouping by village_id, computing AVG(weapons.strength), and selecting only the group with the maximum average. HAVING enters the picture as the filter on the aggregate.

Question. Find the village_id with the highest average weapon strength among hostile inhabitants. Return the village and the average strength.

Input — inhabitants.

id village_id status weapon_id
2 1 hostile 10
5 2 hostile 11
7 2 hostile 12
9 3 friendly 13

Input — weapons.

id strength
10 50
11 80
12 90
13 30

Code.

SELECT i.village_id,
       AVG(w.strength) AS avg_strength
FROM inhabitants i
JOIN weapons w ON w.id = i.weapon_id
WHERE i.status = 'hostile'
GROUP BY i.village_id
ORDER BY avg_strength DESC
LIMIT 1;
Enter fullscreen mode Exit fullscreen mode

Step-by-step explanation.

  1. JOIN inhabitants i with weapons w on the weapon foreign key. Friendly inhabitants are still joined at this stage.
  2. WHERE i.status = 'hostile' removes friendlies before aggregation. Critical — including them would dilute the average.
  3. GROUP BY i.village_id partitions the hostile rows: village 1 (one row: strength 50), village 2 (two rows: 80 and 90 → avg 85).
  4. AVG(w.strength) computes the per-group average.
  5. ORDER BY descending + LIMIT 1 returns the single most dangerous village. (The canonical SQL Island solution often uses HAVING instead of LIMIT — both are valid; HAVING needs the max as a subquery, LIMIT is shorter and more readable.)

Output.

village_id avg_strength
2 85

Rule of thumb. "Find the group with the maximum aggregate" is the textbook pattern for ORDER BY + LIMIT or for a windowed RANK pattern. The game uses the simpler ORDER BY + LIMIT shape because window functions are off the curriculum.

SQL interview question on the GROUP BY + HAVING combo

A senior interviewer might phrase this as: "Given a table of villages with inhabitants and weapons, find every village whose average weapon strength among hostile inhabitants exceeds 75. Walk me through the WHERE-vs-HAVING decision."

Solution Using GROUP BY + HAVING AVG(...) > 75

SELECT i.village_id,
       AVG(w.strength) AS avg_strength
FROM inhabitants i
JOIN weapons w ON w.id = i.weapon_id
WHERE i.status = 'hostile'
GROUP BY i.village_id
HAVING AVG(w.strength) > 75
ORDER BY avg_strength DESC;
Enter fullscreen mode Exit fullscreen mode

Step-by-step trace.

village_id i.status w.strength included?
1 hostile 50 yes — but group avg = 50 (fails HAVING)
2 hostile 80 yes
2 hostile 90 yes — group avg = 85 (passes HAVING)
3 friendly 30 dropped by WHERE

Two groups survive the GROUP BY. Village 1's avg is 50 — fails HAVING. Village 2's avg is 85 — passes. ORDER BY ranks the survivors.

Output:

village_id avg_strength
2 85

Why this works — concept by concept:

  • WHERE filters rows; HAVING filters groupsi.status = 'hostile' is a row-level fact (the inhabitant's status), so it goes in WHERE. AVG(w.strength) > 75 is a property of the group, which does not exist until GROUP BY runs, so it goes in HAVING.
  • Execution order is non-negotiable — SQL runs FROM → JOIN → WHERE → GROUP BY → HAVING → SELECT → ORDER BY. A predicate that references an aggregate cannot appear earlier than HAVING.
  • JOIN before GROUP BY — without the join, the inhabitant's status is in one table and the weapon strength in another. Resolving the per-village average requires the joined view.
  • AVG skips NULLs — if any weapon_id were NULL, the join would drop that row from the average. Quietly. Senior signal: if you mention this when asked, the interviewer ticks the NULL-awareness box.
  • ORDER BY after HAVING — the optional ordering applies to the surviving groups. ORDER BY does not affect which rows survive, only the order they appear.
  • Cost — O(rows) for the JOIN; O(groups) for the aggregate. HAVING is constant per group. The pattern scales linearly with input size; production aggregations of millions of rows execute in milliseconds.

SQL
Topic — group by
GROUP BY problems (SQL)

Practice →


4. The gamified-SQL landscape — Murder Mystery vs SQL Island vs Schemaverse vs CodingGame

Five comparison axes, four games, one honest pick per learner profile

The mental model in one line: gamified SQL is not a single market — it is four very different products that look similar from the outside but train completely different muscle groups. Pick by goal, not by difficulty: Murder Mystery is the chain-JOIN drill, SQL Island is the keyword-broadener, Schemaverse is the strategic-thinking sandbox, CodingGame is the targeted-puzzle library. Once you can name the muscle each one trains, the right pick per learner is obvious.

Visual gamified SQL platforms matrix — four games (SQL Murder Mystery, SQL Island, Schemaverse, CodingGame SQL) compared across difficulty, duration, dialect, narrative immersion, and primary SQL concept taught; on a light PipeCode card.

The four-game comparison matrix.

Axis SQL Murder Mystery SQL Island Schemaverse CodingGame SQL
Difficulty Beginner → Intermediate Absolute Beginner Advanced Beginner → Intermediate
Duration 2 to 3 hours 1 to 2 hours Open-ended, weeks 10 to 30 min puzzles
Dialect SQLite MySQL-flavoured sandbox PostgreSQL MySQL
Narrative immersion High (detective story) High (adventure quest) Very high (multiplayer strategy) Low (puzzle UI)
Primary SQL concepts WHERE, LIKE, chain JOIN, multi-table reasoning WHERE, JOIN, GROUP BY, HAVING, ORDER BY, INSERT/UPDATE/DELETE Stored procedures, triggers, advanced JOIN, planning queries Targeted drills, aggregations, subqueries
Cost Free Free Free (self-hosted) or hosted Free tier + paid
Best for First chain-JOIN lesson Absolute beginners breaking tutorial fatigue Intermediate / advanced strategic thinkers Drill-mode learners after the games

Schemaverse in one paragraph. Schemaverse (schemaverse.com) is a multiplayer space-strategy game where every "move" is a SQL query against a shared PostgreSQL database. Players build fleets, attack other players, and trade resources — but the gameplay is writing SQL. It runs on a self-hosted or community Postgres instance and rewards players who understand stored procedures, triggers, and query planning. The learning curve is steep — Schemaverse assumes you already know basic SELECT + JOIN — but the strategic-thinking dimension is unmatched.

CodingGame SQL in one paragraph. CodingGame (codingame.com) hosts a curated set of small, well-defined SQL puzzles in their general programming-game platform. Each puzzle is a 10 to 30 minute targeted drill — find the second-highest salary, compute the running balance, return the rows that match a specific aggregate pattern. The UX is puzzle-game (timer, leaderboard, achievement badges) rather than story-driven; the SQL dialect is MySQL. It is the closest free product to "PipeCode-style targeted drills wrapped in a gamified UI."

Lost at SQL — the offline complement. Lost at SQL is a physical card game (sold by Octopus Games / Ludicum) where players collaboratively construct SQL queries from cards. Each card is a keyword (SELECT, FROM, WHERE, JOIN) or a value (a table name, a column, a literal). Teams race to build the query that answers a printed puzzle card. It is the only entry on this list that works offline and is purpose-built for classroom / team-building / interview-warmup settings. Not free, but cheap enough for a single bootcamp cohort.

The 30-day plan that uses all of them.

  • Day 1 — SQL Island. Absolute lift-off. By end of day 1 the learner has written 10 to 15 queries and cleared 4 quests.
  • Day 3 — SQL Murder Mystery. Chain JOIN drill on top of Day 1's foundation. By end of day 3 the learner has solved the mystery and unlocked the bonus round.
  • Day 7 — Schemaverse or CodingGame. Branch based on the learner's preference: Schemaverse for strategic thinkers who want a long-running project; CodingGame for drill-mode learners who want quick wins.
  • Day 14 — PipeCode. Window functions, CTEs, and company-tagged interview problems. By Day 14 the learner has 50 to 80 game queries under their belt and is ready to attack the next 70% of the SQL language.
  • Day 30 — Mock interview. End the month with a 60-minute SQL interview against PipeCode's company-tagged problem set — the bridge from "game graduate" to "interview ready."

The honest comparison verdict.

  • For absolute beginners, SQL Island wins by a wide margin. The keyword surface is broader than Murder Mystery, the curve is gentler, and the satisfaction of "escape the island" is the right reward for a first SQL session.
  • For beginners who already wrote some SELECTs, Murder Mystery wins. The chain-JOIN drill is more valuable than another round of GROUP BY.
  • For advanced learners who want strategic depth, Schemaverse wins. There is no comparable product in the gamified-SQL catalogue.
  • For interview-prep candidates, none of the four games is the right primary tool. Games are warmups. The right tool is PipeCode (interview-grade SQL problems, company tags, window functions, CTEs, recursion).

Common interview probes about the landscape.

  • "Which game do you recommend to a junior teammate?" — name the muscle they need, then pick the game that trains it.
  • "Why is CodingGame on the list?" — it is the bridge from story-driven games to interview-style drills.
  • "When do games stop working?" — at window functions, recursive CTEs, and company-flavoured interview patterns. After that, you graduate to targeted libraries.
  • "Have you played Lost at SQL?" — if yes, you have unusual classroom experience; if no, no harm done.

Worked example — picking the right game for a stalled bootcamp cohort

Detailed explanation. A bootcamp lecturer reports that 6 of 12 students dropped during the third SQL lesson (chain JOINs). The choice is not "which game is the best" but "which game fixes this failure mode." The right framework is to map the stall point to the game that drills the missing muscle — not to recommend the most fun game overall.

Question. Given the stall point ("chain JOIN across 3 tables"), pick the game and the specific quest/step that targets the muscle, and design a 90-minute lesson plan.

Input.

stall_point candidate_game candidate_step
Cannot write SELECT + WHERE SQL Island Quest 1
Can write SELECT + WHERE, weak on INNER JOIN SQL Island Quest 2
Can write 2-table JOIN, weak on 3-table chain SQL Murder Mystery Step 3
Can write JOINs, weak on GROUP BY HAVING SQL Island Quests 5-6

Code.

-- The stall-to-game mapping as a single rowset
SELECT stall_point,
       candidate_game,
       candidate_step,
       CASE candidate_game
           WHEN 'SQL Island'         THEN 'sql-island.informatik.uni-kl.de'
           WHEN 'SQL Murder Mystery' THEN 'mystery.knightlab.com'
       END AS url,
       CASE
           WHEN candidate_step LIKE 'Step%' THEN 'Detective story chain'
           WHEN candidate_step LIKE 'Quest%' THEN 'Adventure quest'
       END AS narrative_style
FROM stall_diagnostic
WHERE stall_point = 'Can write 2-table JOIN, weak on 3-table chain';
Enter fullscreen mode Exit fullscreen mode

Step-by-step explanation.

  1. The stall point is the input — a teacher diagnoses what students cannot do.
  2. The candidate game and step is the output — the smallest unit of gamified content that drills that muscle.
  3. CASE chains map each game to its canonical URL and narrative style (detective vs adventure).
  4. WHERE narrows the rowset to a single recommendation; in a real lesson plan, the teacher would remove the WHERE to see every stall-to-game mapping.

Output.

stall_point candidate_game candidate_step url narrative_style
Can write 2-table JOIN, weak on 3-table chain SQL Murder Mystery Step 3 mystery.knightlab.com Detective story chain

Rule of thumb. Always pick the game by stall point, not by total fun. A learner who needs the chain-JOIN drill will get more from Murder Mystery Step 3 than from re-doing SQL Island Quest 5 — even though Quest 5 might be more entertaining in isolation.

Worked example — measuring "did the game work"

Detailed explanation. After a learner finishes a game, the teacher needs an objective check that the targeted muscle actually transferred. The best measure is a tiny "transfer" exercise: a 5-minute SQL question the learner has not seen during the game, but that requires the same concept. If the learner can solve it cold, the game worked; if not, the game functioned as entertainment, not as learning.

Question. Design a 5-question transfer test for a learner who just finished SQL Murder Mystery, with each question targeting one of the concepts the game claims to teach. Score 4/5 or above as "concept transferred."

Input.

concept transfer_question
SELECT + WHERE "List every employee in department 5"
INNER JOIN "Join employees to departments and return employee + dept name"
Chain JOIN (3 tables) "Join employees + departments + locations, return name + city"
LIKE pattern match "Find every employee whose name starts with 'A'"
Compound WHERE "Find every employee in dept 5 OR 7 hired after 2020-01-01"

Code.

-- The transfer test as a rowset; score per row
SELECT concept,
       transfer_question,
       CASE WHEN learner_passed = TRUE THEN 1 ELSE 0 END AS score
FROM transfer_test
WHERE learner_id = 42;
Enter fullscreen mode Exit fullscreen mode

Step-by-step explanation.

  1. Each row is one concept the game claims to teach.
  2. The transfer_question is a novel SQL task that requires the concept but uses a different schema than the game.
  3. The learner attempts each question cold (no hints, no Stack Overflow). The teacher marks learner_passed = TRUE or FALSE.
  4. A score of 4 out of 5 means the concept transferred to a new context — the strongest signal that the game produced durable learning, not just entertainment.

Output.

concept transfer_question score
SELECT + WHERE "List every employee in department 5" 1
INNER JOIN "Join employees to departments and return employee + dept name" 1
Chain JOIN (3 tables) "Join employees + departments + locations, return name + city" 1
LIKE pattern match "Find every employee whose name starts with 'A'" 1
Compound WHERE "Find every employee in dept 5 OR 7 hired after 2020-01-01" 0

Rule of thumb. Never trust a self-report of "I finished the game" as evidence of learning. A 5-question transfer test takes 30 minutes and catches the cases where the learner solved the game by copying solutions from forums.

SQL interview question on game-to-production transfer

A senior interviewer might ask: "You learn SQL primarily through gamified tools. What is the gap between Murder Mystery + SQL Island and a production analytics SQL job, and how would you close it?"

Solution Using a four-axis gap analysis

-- Each gap as a row; close-it action in the rightmost column
SELECT
    gap_axis,
    games_teach,
    production_needs,
    close_with
FROM (VALUES
    ('Dialect',          'SQLite, MySQL-flavoured',  'Postgres, Snowflake, BigQuery',     'PipeCode multi-dialect drills'),
    ('Window functions', 'None',                     'ROW_NUMBER, LAG, SUM OVER',         'PipeCode window function library'),
    ('CTE / recursion',  'None',                     'WITH, recursive CTE',               'PipeCode CTE drills'),
    ('NULL semantics',   'Mostly clean schemas',     'Three-valued logic everywhere',     'PipeCode NULL handling drills')
) AS gap(gap_axis, games_teach, production_needs, close_with);
Enter fullscreen mode Exit fullscreen mode

Step-by-step trace.

gap_axis games_teach production_needs close_with
Dialect SQLite, MySQL-flavoured Postgres, Snowflake, BigQuery PipeCode multi-dialect drills
Window functions None ROW_NUMBER, LAG, SUM OVER PipeCode window function library
CTE / recursion None WITH, recursive CTE PipeCode CTE drills
NULL semantics Mostly clean schemas Three-valued logic everywhere PipeCode NULL handling drills

The four-axis gap analysis names the specific gaps a game-only learner will hit on their first analytics-engineering job. Each gap has a concrete close-it action; none of them are "play more games."

Output:

gap_axis close_with
Dialect PipeCode multi-dialect drills
Window functions PipeCode window function library
CTE / recursion PipeCode CTE drills
NULL semantics PipeCode NULL handling drills

Why this works — concept by concept:

  • Honest scoping — naming the gaps explicitly is the senior signal interviewers reward. A junior pretends games cover everything; a senior names the four axes games leave unaddressed.
  • Dialect specificity — production runs Postgres, Snowflake, BigQuery far more than SQLite or MySQL. A game-only learner will fumble on Postgres window syntax until they drill it.
  • Window functions are 30% of senior interviews — and zero percent of game curricula. The gap closes only with targeted drills.
  • CTEs are the production refactor — every chain JOIN you wrote in Murder Mystery would be rewritten as a CTE in dbt. Recognising that lift is the bridge from gamified shapes to production patterns.
  • NULL three-valued logic — covered nowhere in the games; covered everywhere in production. The PipeCode NULL handling library is the standard fix.
  • Cost — about 20 to 30 hours of targeted practice on PipeCode bridges the gap. No paid tooling required.

SQL
Topic — window functions
Window function problems (SQL)

Practice →


5. The skill-progression map — which game teaches which SQL concept

Seven tiers, four games, one honest ceiling — narrative SQL is the warmup, not the destination

The mental model in one line: every SQL concept lives on a 7-tier ladder, and the four gamified products together cover tiers 1 to 6 — but tier 7 (CTEs, recursive CTEs, window functions) is unreachable by narrative because the concepts do not fit cleanly inside a story. Once you can name the ladder, you know precisely when to stop playing games and start drilling on a real practice library.

Visual skill-progression map — a 7-tier ladder of SQL concepts (SELECT/WHERE, JOIN, GROUP BY/HAVING, ORDER BY, LIKE, DML, CTE/window) with chips showing which game teaches each tier and a 'graduate to PipeCode' arrow at the top; on a light PipeCode card.

The seven-tier ladder bottom-to-top.

  • Tier 1 — Foundation: SELECT + WHERE. Covered by SQL Island Quests 1 to 2 and Murder Mystery Steps 1 to 2. The "look at one table and filter rows" primitive. About 15 minutes of game time to cover.
  • Tier 2 — JOIN (the make-or-break). Covered by SQL Island Quests 2 to 4 (one-step joins) and Murder Mystery Steps 3 to 4 (chain joins across 3 to 4 tables). The single biggest skill unlock in beginner SQL.
  • Tier 3 — Aggregation: GROUP BY, HAVING, COUNT. Covered by SQL Island Quests 5 to 6 and CodingGame SQL puzzles. The lesson that finally distinguishes WHERE (row-level) from HAVING (group-level).
  • Tier 4 — ORDER BY + LIMIT. Covered by SQL Island Quest 4 and many CodingGame puzzles. The "top-N" pattern that dominates production analytics dashboards.
  • Tier 5 — Pattern matching: LIKE / ILIKE. Covered by Murder Mystery's final step (the killer's transcript uses LIKE pattern probes). Lightly touched in SQL Island.
  • Tier 6 — DML: INSERT, UPDATE, DELETE. Covered by SQL Island's endgame and Schemaverse moves. Most tutorials skip DML entirely — gamified SQL is the rare medium that includes it because story progression requires writing changes.
  • Tier 7 — Advanced: CTEs, subqueries, window functions. Not covered by any game. CTEs appear only in passing in CodingGame; window functions are absent everywhere. This is where games stop and PipeCode begins.

Why games cannot teach Tier 7.

  • Narrative needs simple verbs. "Find the killer" maps cleanly to JOIN + WHERE. "Find the killer using a recursive CTE that walks the employee hierarchy" does not — the story collapses under the abstraction.
  • Window functions need real datasets. ROW_NUMBER, LAG, and LEAD only become interesting on tables with hundreds of rows of time-series-like data. Toy schemas (8 inhabitants, 4 weapons) cannot generate enough interesting partitions for the function to feel useful.
  • Interview-grade SQL needs targeted drills. "Find the second-highest salary," "compute the running balance," "deduplicate keeping the latest row" are all canonical interview patterns that need to be drilled in isolation — not embedded in a story that distracts from the pattern.
  • The narrative wrapper has a complexity ceiling. Once a query needs three nested subqueries or a recursive CTE, the prose required to set up the puzzle becomes longer than the query itself. The game becomes a worse delivery mechanism than a plain exercise.

The honest ceiling stated bluntly.

  • Games cover the first 30% of SQL. That 30% is the foundation. Without it, you cannot write any analytics SQL at all.
  • Games do not cover the next 70%. That 70% is what gets you a job. Window functions, CTEs, recursion, multi-step subqueries, NULL semantics, query optimisation, EXPLAIN plans — none of these fit inside a story.
  • The transition is sharp. Once you have cleared SQL Island and SQL Murder Mystery, doing them again will not unlock Tier 7. You have to switch tools.

The PipeCode handoff.

Common interview probes about the progression.

  • "What concept did you learn last in SQL?" — naming a Tier 6 or Tier 7 concept is the right signal. Naming Tier 1 ("I just learned SELECT") suggests you have not graduated games yet.
  • "What did SQL Murder Mystery not teach you?" — the right answer is "window functions, CTEs, and NULL handling."
  • "How would you teach SQL to a junior?" — the right answer is the 30-day plan: games → CodingGame → PipeCode → mock interview.

Worked example — mapping a learner's "I can do X" to the ladder

Detailed explanation. When a learner says "I know SQL," the interviewer's first task is to triangulate where on the 7-tier ladder they actually live. A clean way is to ask three "show me" probes that span different tiers; the highest tier where the learner can produce working code is their actual ceiling.

Question. Build a 3-probe ladder-locator that maps a learner's actual ceiling to one of the 7 tiers, and recommend the next two tools.

Input.

probe tier what it tests
"Find the top-3 highest-paid employees per department" 7 window functions (ROW_NUMBER)
"Find the top-3 highest-paid employees overall" 4 ORDER BY + LIMIT
"Find every employee in department 5" 1 SELECT + WHERE

Code.

SELECT learner_id,
       CASE
           WHEN probe7_passed = TRUE THEN 7
           WHEN probe4_passed = TRUE THEN 4
           WHEN probe1_passed = TRUE THEN 1
           ELSE 0
       END AS ladder_tier,
       CASE
           WHEN probe7_passed = TRUE THEN 'PipeCode company-tagged interview problems'
           WHEN probe4_passed = TRUE THEN 'PipeCode window functions + CTE drills'
           WHEN probe1_passed = TRUE THEN 'SQL Island Quests 2-6, then PipeCode'
           ELSE 'SQL Island Quest 1 (absolute start)'
       END AS next_tool
FROM ladder_diagnostic;
Enter fullscreen mode Exit fullscreen mode

Step-by-step explanation.

  1. Each probe targets one tier. Probe 7 is the hardest (window function); Probe 1 is the easiest (basic WHERE).
  2. The CASE chain short-circuits on the first TRUE — pass Probe 7 and you land at tier 7 regardless of the easier probes.
  3. The next_tool column maps each tier to the actionable next step. Tier 7 learners skip the games and go straight to PipeCode; tier 1 learners start with SQL Island Quest 1.
  4. Probe 4 is a useful intermediate diagnostic — a learner who can solve "top 3 overall" but not "top 3 per group" has a precise gap (window functions) that PipeCode drills target.

Output.

learner_id ladder_tier next_tool
1 7 PipeCode company-tagged interview problems
2 4 PipeCode window functions + CTE drills
3 1 SQL Island Quests 2-6, then PipeCode
4 0 SQL Island Quest 1 (absolute start)

Rule of thumb. Always probe the hardest tier first. A learner who passes Probe 7 has likely already cleared 1 to 6 — you save 4 probes by ladder-walking top down.

Worked example — when re-playing a game adds nothing

Detailed explanation. A learner who has cleared SQL Island and Murder Mystery often asks "should I play again?" The answer is almost always no — the marginal value of a second playthrough drops sharply because the surprise (the dopamine driver) is gone. Time spent re-playing is better spent on a Tier 7 drill that the games cannot cover.

Question. Compute the diminishing-returns curve of game replays vs PipeCode drills for a learner who has cleared both Murder Mystery and SQL Island. Recommend the higher-value tool.

Input.

activity session_n concepts_drilled new_keyword_introduced
Replay SQL Island 2 repeat tiers 1-6 no
Replay Murder Mystery 2 repeat tier 2 (chain JOIN) no
PipeCode window functions 1 tier 7 yes — ROW_NUMBER, LAG
PipeCode CTE drills 1 tier 7 yes — WITH, recursive

Code.

SELECT activity,
       session_n,
       concepts_drilled,
       new_keyword_introduced,
       CASE WHEN new_keyword_introduced = 'yes' THEN 'high value' ELSE 'low value' END AS recommendation
FROM activity_value
ORDER BY recommendation DESC;
Enter fullscreen mode Exit fullscreen mode

Step-by-step explanation.

  1. Each row is an activity option for the learner's next session.
  2. The new_keyword_introduced column is the binary signal: does the activity teach a keyword the learner has not yet seen?
  3. The CASE turns that signal into a "high value" / "low value" recommendation.
  4. ORDER BY puts the high-value options on top — exactly the order the learner should attempt them.
  5. The diminishing-returns insight is captured in the fact that two of the four rows ("replay X") return "low value" — replaying a finished game does not introduce new keywords, so the marginal learning is near zero.

Output.

activity new_keyword_introduced recommendation
PipeCode window functions yes high value
PipeCode CTE drills yes high value
Replay SQL Island no low value
Replay Murder Mystery no low value

Rule of thumb. Replays of finished games are entertainment, not learning. Once you have cleared a game, the next session should introduce a new keyword — which means switching tools, not switching savefiles.

SQL interview question on the game-to-PipeCode graduation

A senior interviewer often closes with: "You finished both gamified games. Write a query that distinguishes the top-paid employee per department — the canonical window-function pattern that no game teaches. Walk me through why a JOIN-only solution is harder."

Solution Using ROW_NUMBER() OVER (PARTITION BY ...)

-- The window-function answer — clean, scales, and is the canonical pattern
SELECT department_id, employee_id, salary
FROM (
    SELECT
        e.department_id,
        e.employee_id,
        e.salary,
        ROW_NUMBER() OVER (PARTITION BY e.department_id ORDER BY e.salary DESC) AS rn
    FROM employees e
) ranked
WHERE rn = 1;
Enter fullscreen mode Exit fullscreen mode

Step-by-step trace.

department_id employee_id salary rn
10 1 100 1
10 2 90 2
10 3 80 3
20 4 200 1
20 5 150 2

The window function partitions by department_id, sorts each partition by salary DESC, and assigns a row number. Outer WHERE keeps only rn = 1 — the top-paid per department.

Output:

department_id employee_id salary
10 1 100
20 4 200

Why this works — concept by concept:

  • ROW_NUMBER as a per-group ranker — the window function assigns 1, 2, 3, ... within each partition independently. It is the production-grade replacement for "ORDER BY + LIMIT per group," which no game teaches.
  • PARTITION BY is the per-group equivalent of GROUP BY — same semantic ("split rows by this key") but the result preserves the rows instead of collapsing them into one row per group.
  • ORDER BY inside OVER — the ranking direction. DESC for "highest first"; ASC for "lowest first." Independent of any outer ORDER BY on the final result.
  • Outer WHERE on the aliasrn = 1 keeps only the top of each partition. The alias rn can only be referenced in the outer query because window functions are evaluated in a separate semantic phase.
  • Why a JOIN-only solution is harder — the equivalent without window functions requires a self-join: JOIN employees a ON a.department_id = e.department_id AND a.salary > e.salary to find each employee with a "higher-paid same-department employee," then filtering to NULL on that JOIN — a fragile, hard-to-read shape that the window function replaces in three lines.
  • Cost — O(rows) sort per partition; total cost O(n log n) in the dominant term. Production engines partition-sort efficiently. This is the canonical pattern; PipeCode's window functions practice library drills it into muscle memory.

SQL
Topic — CTE
CTE problems (SQL)

Practice →


Cheat sheet — gamified SQL recipes

  • Tutorial fatigue diagnosis. If a learner quit after exercise 4 of a SQL tutorial, recommend SQL Island Quest 1 immediately — story-driven SQL has a measurably higher 30-minute completion rate than exercise-driven SQL.
  • First chain-JOIN lesson. Use SQL Murder Mystery Steps 1 to 3 as a 60-minute classroom exercise. Stops every "I cannot JOIN" complaint in a bootcamp cohort.
  • First GROUP BY lesson in a story. SQL Island Quests 5 to 6 ("count survivors per village" → "find the strongest village") teach GROUP BY + HAVING with zero abstract examples.
  • Multiplayer SQL session for a team. Schemaverse on a self-hosted Postgres — every move is a SQL query, every player competes against the others. Highest engagement of any SQL tool for advanced learners.
  • Bridge from games to interview drills. CodingGame SQL puzzles — same gamified UI as Murder Mystery, but the puzzles are interview-flavoured rather than story-flavoured.
  • After games, drill window functions on PipeCode. No game teaches ROW_NUMBER / LAG / LEAD; the window functions library is the canonical next stop.
  • After games, drill CTEs on PipeCode. No game teaches WITH ... AS or recursive CTEs; the CTE practice library is the canonical next stop.
  • Bridge from toy schemas to production. Pair the games with a real dataset (Kaggle NYC taxi, the Stack Overflow dump, or Mode's free analytics dataset) for the "transfer to real data" step.
  • Classroom / team-building offline. Lost at SQL — the only physical card game on the list — works for bootcamp cohorts and interview-warmup sessions where laptops are not on.
  • 30-day learning plan. Day 1 SQL Island, Day 3 Murder Mystery, Day 7 CodingGame or Schemaverse, Day 14 PipeCode. By Day 30 you have written 200+ queries and are ready to attempt a SQL interview.
  • Track progress per quest. Gamification works only if the reward loop is visible. Mark "Quest 4 cleared" / "Step 3 cleared" in a spreadsheet — the brain treats the checkmark as a reward and writes the next query for free.
  • Never re-play a finished game. Marginal learning approaches zero on a second playthrough. Switch to a different game (or to PipeCode) instead.

Frequently asked questions

What is the SQL Murder Mystery and how long does it take?

SQL Murder Mystery is a free browser-based detective game built by the Knight Lab at Northwestern University. You play a detective investigating a murder in fictional "SQL City" on January 15, 2018, and your only tool is read access to the city's SQLite database. You write 8 to 10 SQL queries across four to six tables (crime_scene_report, person, drivers_license, interview, get_fit_now_member, get_fit_now_check_in, income, facebook_event_checkin) to chain through clues until you identify the killer. A typical playthrough takes 2 to 3 hours for an intermediate beginner. It teaches SELECT, WHERE, LIKE, INNER JOIN, and chain joins across three or four tables — exactly the muscle most beginners struggle with. Play it at mystery.knightlab.com — no signup required.

What is SQL Island and where do I start?

SQL Island is a free browser-based adventure game originally written in German at HCI University of Applied Sciences Kaiserslautern and now widely used in US bootcamps via an English mirror. You play a plane crash survivor on a tropical island and must clear 8 quests — each one a SQL query against a small relational schema of inhabitants, items, weapons, and friends — to build a raft and escape. Quests progress from a simple WHERE filter (Quest 1) to JOINs (Quests 2 to 4), aggregations with GROUP BY and HAVING (Quests 5 to 6), and basic DML with INSERT / UPDATE / DELETE (Quests 7 to 8). Total playtime is 1 to 2 hours. Start at Quest 1 — even if you already know SELECT, the lift-off matters and the early quests are 90 seconds each. Play it at sql-island.informatik.uni-kl.de.

Are SQL games actually effective for learning?

Yes — for the first 30% of the language. Empirical bootcamp data and self-reported learner surveys both show that narrative-driven SQL games have a 30-minute completion rate that is significantly higher than static exercise lists, because the story rewards every successful query with a visible progress beat. Games teach SELECT, WHERE, INNER JOIN, GROUP BY, HAVING, ORDER BY, LIMIT, LIKE, and basic DML in a way that sticks — students retain the concepts because they associated them with story events ("the witness lives at the last house on Northwestern Drive"). However, games do not teach window functions, CTEs, recursive CTEs, multi-step subqueries, NULL semantics, or query optimisation — because those concepts do not fit cleanly inside a story. After games, graduate to a targeted practice library like PipeCode's SQL drills.

Which is harder, SQL Murder Mystery or SQL Island?

SQL Murder Mystery is the harder of the two, and not because it covers more keywords (it actually covers fewer). The difficulty spike is in Step 3 — the chain JOIN across three or four tables (get_fit_now_check_in JOIN get_fit_now_member JOIN person JOIN drivers_license) — which forces beginners to hold three intermediate results in their head while composing the JOIN order. SQL Island has a gentler curve: each quest adds exactly one new keyword on top of the previous one, so the cognitive load per quest is lower. For absolute beginners, play SQL Island first. For learners who can already write basic SELECT + JOIN and need the chain-JOIN drill, jump straight to Murder Mystery. Most bootcamps run SQL Island as Day 1 and Murder Mystery as Day 3 — that order tracks the difficulty curve.

What should I do after I finish all the SQL games?

Graduate to targeted, interview-flavoured drills — the games' coverage stops at GROUP BY and basic DML, but the next 70% of the language (window functions, CTEs, recursion, NULL semantics, multi-dialect portability, query optimisation) is where senior interviews and production analytics jobs live. The canonical next stop is a structured practice library with company tags — PipeCode covers all of these with a real-time scoring engine and a curated set of FAANG-tagged problems. Recommended order: window functions first (the highest-leverage interview concept), CTEs second, NULL handling third, then company-tagged interview problems closer to your target interview date. The full SQL for data engineering interviews course is the long-form path; the SQL practice topic is the drill path.

Can I use SQL games to teach a class or bootcamp?

Yes — and they work especially well for the first 1 to 3 lessons of a SQL module. The canonical lesson plan: Day 1 is SQL Island Quests 1 to 4 (90 minutes, 12 to 16 queries, covers SELECT + WHERE + INNER JOIN) — students leave with a "raft to escape" payoff. Day 2 is SQL Island Quests 5 to 8 (covers GROUP BY, HAVING, DML). Day 3 is SQL Murder Mystery Steps 1 to 3 (chain JOIN drill, ~60 minutes). Day 4 is the bonus round (GROUP BY + HAVING combined with chain JOIN). From Day 5 onward, switch to targeted drills on CodingGame SQL puzzles and PipeCode practice problems — the games' marginal value flattens after the keyword surface is covered. For offline classroom activities, the Lost at SQL card game works well as a team-building / interview-warmup exercise.

Practice on PipeCode

Pipecode.ai is Leetcode for Data Engineering — every gamified concept above ships with hands-on practice rooms where you write the JOIN, the GROUP BY, the window function, and the CTE against real graded inputs. PipeCode pairs every reading with 450+ DE-focused problems and a real-time scoring engine, so once you have escaped the island and solved the murder, the next 70% of SQL — window functions, CTEs, NULL handling, company-tagged interview patterns — is one practice room away.

Practice SQL now →
Window function drills →

Top comments (0)