SQL games guide
SQL Murder Mystery: hints, walkthrough and solution
The SQL Murder Mystery is a free browser game from the Knight Lab at Northwestern University. There was a
murder in SQL City on January 15, 2018, and you find the killer with SQL queries on a police database. To
start, open mystery.knightlab.com and query the
crime_scene_report table. If you are stuck, open the hints for your step. Each step also shows its
query and its real result.
Show the answer: who is the killer?
The killer is Jeremy Bowers. The person who hired him is Miranda Priestly. The game has two parts: part 1 finds the killer, and part 2 finds the person behind the murder.
Where are you stuck in the SQL Murder Mystery?
Find the line that matches what you have now in the SQL Murder Mystery, and go to that step.
| What you have now | Go to |
|---|---|
| You have the prompt, and you have not run a query yet. | Part 1, step 1: Find the crime scene report |
| A crime scene report that describes two witnesses. | Part 1, step 2: Find the first witness |
| The first witness: person 14887, at the last house on Northwestern Dr. | Part 1, step 3: Find the second witness |
| The ids of both witnesses, 14887 and 16371. | Part 1, step 4: Read the two interviews |
| Two interview transcripts: a gym bag, a 48Z membership, a car plate with H42W. | Part 1, step 5: Check the gym clue |
| Two gold 48Z gym members who were at the gym on January 9. | Part 1, step 6: Check the car plate |
| Three people with an H42W car plate. | Part 1, step 7: Put the clues in one query |
| The game replied "Congrats, you found the murderer! But wait, there's more..." | Part 2, step 1: Read the killer's interview |
| The killer's interview: a red-haired woman with a Tesla Model S. | Part 2, step 2: Find the women who match the description |
| Three red-haired women who drive a Tesla Model S. | Part 2, step 3: Find who went to the concert 3 times |
| Two people who went to the SQL Symphony Concert 3 times in December 2017. | Part 2, step 4: Put the clues in one query |
How do you play the SQL Murder Mystery?
You play the SQL Murder Mystery in your browser, with no account and no install. You play in five steps:
- Open mystery.knightlab.com and read the prompt: a murder, on January 15, 2018, in SQL City.
- Look at the tables. The game runs on SQLite, so
SELECT name FROM sqlite_master WHERE type = 'table'lists them. The page also has a schema diagram. - Write a query in one of the boxes and run it. Each result gives you a clue for the next query.
- Follow the clues through the tables until one person is left.
- Check your answer with the game's
solutiontable.
To check an answer, run these two statements with the name that you found:
INSERT INTO solution VALUES (1, 'Name Here');
SELECT value FROM solution; A wrong name gets the reply "That's not the right person. Try again!" The killer's name gets "Congrats, you found the murderer! But wait, there's more..." and that reply starts part 2.
What tables are in the SQL Murder Mystery database?
The SQL Murder Mystery database has 9 tables. Most of the case is about connecting them by their ids, so keep this list open while you play.
| Table | What it holds | Columns that link |
|---|---|---|
crime_scene_report | Police reports: date (a number such as 20180115), type of crime, a description and the city. | |
person | Every person: name, address and the ids that link to other tables. | id, license_id, ssn |
interview | What people told the police. | person_id |
drivers_license | Age, height, eye and hair color, gender, car and plate number. | id |
get_fit_now_member | Members of the Get Fit Now Gym and their membership status. | id (such as 48Z55), person_id |
get_fit_now_check_in | Each gym visit, with the date and times. | membership_id |
facebook_event_checkin | Each check-in at an event, with the event name and date. | person_id |
income | Annual income. | ssn |
solution | Where you put your answer to check it. |
The links between tables: person.license_id = drivers_license.id,
person.ssn = income.ssn, and person_id in the other tables =
person.id. A gym visit links to a member by membership_id = get_fit_now_member.id.
Why does my SQL Murder Mystery query return no rows?
A SQL Murder Mystery query returns no rows when a filter does not match the data exactly. Look at three things first: the dates are numbers such as 20180115, the = sign matches letter case exactly, and a LIKE pattern can be too narrow. Each item is a wrong turn, with what you get and what to write.
-
You typed
date = '2018-01-15'You get 0 rows
Write
date = 20180115The date column is a number, not a date, so text never matches it. See Part 1, step 1.
-
You typed
type = 'Murder' or city = 'sql city'You get 0 rows
Write
type = 'murder' AND city = 'SQL City'With =, the letter case must match the data exactly. See Part 1, step 1.
-
You typed
address_street_name = 'Northwestern Drive'You get 0 rows
Write
address_street_name = 'Northwestern Dr'The data uses the short form of the street name, as the report does. See Part 1, step 2.
-
You typed
ORDER BY address_number LIMIT 1You get the wrong person: Kinsey Erickson, house 309
Write
ORDER BY address_number DESC LIMIT 1Without DESC, the sort goes from low to high, so you get the first house, not the last. See Part 1, step 2.
-
You typed
name = 'Annabel'You get 0 rows
Write
name LIKE 'Annabel%'The name column holds full names, so the first name alone matches nobody. See Part 1, step 3.
-
You typed
check_in_date = '2018-01-09'You get 0 rows
Write
check_in_date = 20180109Gym dates are numbers too. See Part 1, step 5.
-
You typed
plate_number LIKE 'H42W%'You get one plate, H42W0X, and the driver is a woman
Write
plate_number LIKE '%H42W%'The witness said the plate includes H42W, not that it starts with H42W. The pattern without the first % finds only one plate, and it belongs to a woman. See Part 1, step 6.
-
You typed
hair_color = 'Red' or car_model = 'Tesla Model S'You get 0 rows
Write
hair_color = 'red' AND car_make = 'Tesla' AND car_model = 'Model S'Hair colors are lowercase, and the make and the model are two columns. See Part 2, step 2.
-
You typed
WHERE event_name = 'SQL Symphony Concert' (no date)You get 25 people with 3 visits, not 2
Write
date BETWEEN 20171201 AND 20171231Without the date filter, you count visits from all of the data, not from December 2017. See Part 2, step 3.
SQL Murder Mystery walkthrough, part 1: who is the killer?
The killer in the SQL Murder Mystery is one man, and 7 queries get you from the crime scene report to his name. Each step shows a first hint. Open the second hint, and then the query, only when you need them.
Part 1, step 1: Find the crime scene report
Get the report for the murder on January 15, 2018, in SQL City.
Hint 1: The report is in the crime_scene_report table. The prompt gives you three facts that pick one row.
Hint 2
Filter on date, type and city. The date column is a number in the form 20180115, not a date. Without the city filter, the query returns 3 murders on that date: in Albany, Reno and SQL City.
Show the query and the result
SELECT *
FROM crime_scene_report
WHERE date = 20180115
AND type = 'murder'
AND city = 'SQL City'; | date | type | description | city |
|---|---|---|---|
| 20180115 | murder | Security footage shows that there were 2 witnesses. The first witness lives at the last house on "Northwestern Dr". The second witness, named Annabel, lives somewhere on "Franklin Ave". | SQL City |
What you learn: Two witnesses: the last house on Northwestern Dr, and a person named Annabel on Franklin Ave.
Part 1, step 2: Find the first witness
Find the person who lives at the last house on Northwestern Dr.
Hint 1: Addresses are in the person table, in the columns address_number and address_street_name.
Hint 2
50 people live on Northwestern Dr. The last house has the highest address_number, so sort from high to low and keep the first row.
Show the query and the result
SELECT id, name, address_number, address_street_name
FROM person
WHERE address_street_name = 'Northwestern Dr'
ORDER BY address_number DESC
LIMIT 1; | id | name | address_number | address_street_name |
|---|---|---|---|
| 14887 | Morty Schapiro | 4919 | Northwestern Dr |
What you learn: The first witness is person 14887.
Part 1, step 3: Find the second witness
Find the person named Annabel who lives on Franklin Ave.
Hint 1: Use the person table again. You know only the first name, so match the start of the name.
Hint 2
LIKE 'Annabel%' matches every name that starts with Annabel. 4 people match it, so also filter on the street.
Show the query and the result
SELECT id, name, address_number, address_street_name
FROM person
WHERE address_street_name = 'Franklin Ave'
AND name LIKE 'Annabel%'; | id | name | address_number | address_street_name |
|---|---|---|---|
| 16371 | Annabel Miller | 103 | Franklin Ave |
What you learn: The second witness is person 16371.
Part 1, step 4: Read the two interviews
Read what the two witnesses told the police.
Hint 1: The interview table has a person_id column. Use the two ids that you found.
Hint 2
IN (14887, 16371) matches both ids in one query.
Show the query and the result
SELECT person_id, transcript
FROM interview
WHERE person_id IN (14887, 16371); | person_id | transcript |
|---|---|
| 14887 | I heard a gunshot and then saw a man run out. He had a "Get Fit Now Gym" bag. The membership number on the bag started with "48Z". Only gold members have those bags. The man got into a car with a plate that included "H42W". |
| 16371 | I saw the murder happen, and I recognized the killer from my gym when I was working out last week on January the 9th. |
What you learn: The killer is a man, a gold member of Get Fit Now Gym with a membership id that starts with 48Z. The second witness saw him at the gym on January 9. His car plate includes H42W.
Part 1, step 5: Check the gym clue
Find the gold members with a 48Z id who were at the gym on January 9, 2018.
Hint 1: Members are in get_fit_now_member. Visits are in get_fit_now_check_in. The two tables share the membership id.
Hint 2
Join the tables on get_fit_now_check_in.membership_id = get_fit_now_member.id. Then filter on the id, the gold status and check_in_date = 20180109.
Show the query and the result
SELECT get_fit_now_member.id, get_fit_now_member.name,
get_fit_now_member.membership_status
FROM get_fit_now_member
JOIN get_fit_now_check_in
ON get_fit_now_check_in.membership_id = get_fit_now_member.id
WHERE get_fit_now_member.id LIKE '48Z%'
AND get_fit_now_member.membership_status = 'gold'
AND get_fit_now_check_in.check_in_date = 20180109; | id | name | membership_status |
|---|---|---|
| 48Z7A | Joe Germuska | gold |
| 48Z55 | Jeremy Bowers | gold |
What you learn: Two members match, so the gym clue alone does not decide. Use the car plate.
Part 1, step 6: Check the car plate
Find the people whose car plate includes H42W.
Hint 1: Plates are in drivers_license. Names are in person. person.license_id points to drivers_license.id.
Hint 2
LIKE '%H42W%' matches H42W at any position in the plate.
Show the query and the result
SELECT person.name, drivers_license.plate_number, drivers_license.gender
FROM person
JOIN drivers_license ON drivers_license.id = person.license_id
WHERE drivers_license.plate_number LIKE '%H42W%'; | name | plate_number | gender |
|---|---|---|
| Tushar Chandra | 4H42WR | male |
| Jeremy Bowers | 0H42W2 | male |
| Maxine Whitely | H42W0X | female |
What you learn: One name is in both lists: Jeremy Bowers.
Part 1, step 7: Put the clues in one query
Get the one person who has an H42W plate and a gold membership with a 48Z id.
Hint 1: Join three tables: person, drivers_license and get_fit_now_member.
Hint 2
get_fit_now_member.person_id points to person.id. Keep the plate filter, the 48Z id filter and the gold filter.
Show the query and the result
SELECT person.id, person.name
FROM person
JOIN drivers_license ON drivers_license.id = person.license_id
JOIN get_fit_now_member ON get_fit_now_member.person_id = person.id
WHERE drivers_license.plate_number LIKE '%H42W%'
AND get_fit_now_member.id LIKE '48Z%'
AND get_fit_now_member.membership_status = 'gold'; | id | name |
|---|---|
| 67318 | Jeremy Bowers |
What you learn: The killer is Jeremy Bowers, person 67318.
SQL Murder Mystery walkthrough, part 2: who hired the killer?
Part 2 of the SQL Murder Mystery starts from the killer's interview, and it ends with the name of the person who paid him. Each step shows a first hint, and the query is one click further.
Part 2 in 2 queries
The game challenges you to finish part 2 in no more than 2 queries. You can:
- Read the killer's interview: Part 2, step 1: Read the killer's interview.
- Put every clue in one query, with a subquery for the concert: Part 2, step 4: Put the clues in one query.
Steps 2 and 3 show the same clues one at a time, if you want to see each list first.
Part 2, step 1: Read the killer's interview
Read what Jeremy Bowers told the police.
Hint 1: Use the interview table with his person id.
Hint 2
His person id is 67318.
Show the query and the result
SELECT transcript
FROM interview
WHERE person_id = 67318; | transcript |
|---|
| I was hired by a woman with a lot of money. I don't know her name but I know she's around 5'5" (65") or 5'7" (67"). She has red hair and she drives a Tesla Model S. I know that she attended the SQL Symphony Concert 3 times in December 2017. |
What you learn: A woman, 65 to 67 inches tall, red hair, a Tesla Model S, at the SQL Symphony Concert 3 times in December 2017.
Part 2, step 2: Find the women who match the description
Find the drivers who match her height, hair and car.
Hint 1: Height, hair color, gender and car are all columns of drivers_license.
Hint 2
BETWEEN 65 AND 67 keeps both ends. Without the height filter, 3 drivers still match, so you need the concert clue too.
Show the query and the result
SELECT person.id, person.name, drivers_license.height
FROM person
JOIN drivers_license ON drivers_license.id = person.license_id
WHERE drivers_license.gender = 'female'
AND drivers_license.hair_color = 'red'
AND drivers_license.car_make = 'Tesla'
AND drivers_license.car_model = 'Model S'
AND drivers_license.height BETWEEN 65 AND 67; | id | name | height |
|---|---|---|
| 78881 | Red Korb | 65 |
| 90700 | Regina George | 66 |
| 99716 | Miranda Priestly | 66 |
What you learn: Three women match. The concert clue decides.
Part 2, step 3: Find who went to the concert 3 times
Find the people who checked in at the SQL Symphony Concert 3 times in December 2017.
Hint 1: Check-ins are in facebook_event_checkin, one row for each check-in.
Hint 2
Count the rows for each person_id with GROUP BY, and keep the groups where the count is 3 with HAVING.
Show the query and the result
SELECT person_id, COUNT(*) AS visits
FROM facebook_event_checkin
WHERE event_name = 'SQL Symphony Concert'
AND date BETWEEN 20171201 AND 20171231
GROUP BY person_id
HAVING COUNT(*) = 3; | person_id | visits |
|---|---|
| 24556 | 3 |
| 99716 | 3 |
What you learn: Person 99716 is in both lists: Miranda Priestly.
Part 2, step 4: Put the clues in one query
Get the one woman with red hair and a Tesla Model S who went to the concert 3 times.
Hint 1: Put the concert query inside the description query as a subquery.
Hint 2
Use person.id IN (the concert query). Join income on ssn if you want to see her money too.
Show the query and the result
SELECT person.name, income.annual_income
FROM person
JOIN drivers_license ON drivers_license.id = person.license_id
JOIN income ON income.ssn = person.ssn
WHERE drivers_license.gender = 'female'
AND drivers_license.hair_color = 'red'
AND drivers_license.car_make = 'Tesla'
AND drivers_license.car_model = 'Model S'
AND person.id IN (
SELECT person_id
FROM facebook_event_checkin
WHERE event_name = 'SQL Symphony Concert'
AND date BETWEEN 20171201 AND 20171231
GROUP BY person_id
HAVING COUNT(*) = 3
); | name | annual_income |
|---|---|
| Miranda Priestly | 310000 |
What you learn: The person who hired the killer is Miranda Priestly.
Which SQL do you need for the SQL Murder Mystery?
You can solve the SQL Murder Mystery with WHERE, LIKE and one join at a time. The walkthrough also joins three tables and uses GROUP BY, HAVING and one subquery, so that each step is one query. Each row names the first walkthrough step that uses the SQL, with a free lesson for it.
| SQL | First used in | Free lesson |
|---|---|---|
WHERE | Part 1, step 1: Find the crime scene report | WHERE |
AND | Part 1, step 1: Find the crime scene report | AND, OR and NOT |
ORDER BY | Part 1, step 2: Find the first witness | ORDER BY |
LIMIT | Part 1, step 2: Find the first witness | LIMIT |
LIKE | Part 1, step 3: Find the second witness | BETWEEN, IN and LIKE |
IN | Part 1, step 4: Read the two interviews | BETWEEN, IN and LIKE |
INNER JOIN | Part 1, step 5: Check the gym clue | INNER JOIN |
A join on three tables | Part 1, step 7: Put the clues in one query | Joins on more than two tables |
BETWEEN | Part 2, step 2: Find the women who match the description | BETWEEN, IN and LIKE |
GROUP BY | Part 2, step 3: Find who went to the concert 3 times | GROUP BY |
HAVING | Part 2, step 3: Find who went to the concert 3 times | HAVING |
A subquery in WHERE | Part 2, step 4: Put the clues in one query | Subqueries in WHERE |
What should you play after the SQL Murder Mystery?
After the SQL Murder Mystery, play SQL Block Game. The murder case uses WHERE in every step, and ORDER BY, LIMIT and GROUP BY too. SQL Block Game drills those clauses at speed. Query cards fall, and you write the SQL that answers each one before it lands. It runs real PostgreSQL in your browser, it is free, and every run shuffles the cards.
Play SQL Block Game →For more detective games and how they compare, read our ranking of the best SQL games. For a story that teaches window functions and recursive CTEs, play Station Zero.
SQL Murder Mystery questions
Who made the SQL Murder Mystery?
Joon Park and Cathy He made it while they were fellows at the Knight Lab of Northwestern University. Joe Germuska made the web version. The game is free, and you play it in your browser.
Can you play the SQL Murder Mystery offline?
Yes. Download the file sql-murder-mystery.db from the game’s GitHub repository and open it in a SQLite tool. The repository suggests SQLiteStudio.
Do the SQL Murder Mystery queries work in PostgreSQL?
The 11 walkthrough queries return the same rows in PostgreSQL 17.5 with the game data loaded. Four things from the game do not work the same way. PostgreSQL has no sqlite_master table, so use information_schema.tables to list tables. PostgreSQL reads "SQL City" in double quotes as a column name, so put text in single quotes. LIKE 'annabel%' finds 4 people in the game, but 0 in PostgreSQL, because PostgreSQL LIKE does not ignore case. And the answer check is a SQLite trigger in the game's database file, so it does not exist in PostgreSQL.
How long does the SQL Murder Mystery take?
About 45 minutes, in our own play. If you get stuck, open the hints for the step you are on.
The SQL Murder Mystery is by Joon Park and Cathy He, Northwestern University Knight Lab. The case text and the database rows quoted on this page are from the game's GitHub repository and are licensed CC BY-SA 4.0. SQLMaxx did not make this game.