Blog›SQL Murder Mystery: A Walkthrough That Doesn't Spoil It
Getting StartedSQL Skills
SQL Murder Mystery A Walkthrough That Does Not Spoil It
Most walkthroughs just hand you the killer's name, which wastes the puzzle. This one shows you the method, explains every query, and leaves the finding to you.
CR
Conor Robertson
August 7, 2026 · 11 min read
Frequently asked questions
The questions that come up most when people get stuck on this one.
Ready to practice on real data?
QueryCase teaches SQL through mystery cases on real datasets. Music, sports, film, and more. Your first cases are completely free.
There has been a murder in SQL City. You know the date, you know the city, and you have a database of nine tables that nobody has explained to you. That is the whole brief.
The SQL Murder Mystery by Northwestern University's Knight Lab is the best free hour in SQL learning, and it is beloved for a good reason: it drops you into the exact situation every analyst faces on their first day in a new job. An unfamiliar schema, a vague question, and no map.
Most walkthroughs you will find for it do you a disservice. They paste the final query, name the killer, and you close the tab having learned nothing except that somebody on the internet finished a puzzle. Knight Lab's own walkthrough deliberately refuses to name the murderer, and they are right.
So this one is built differently. Every query below has the crucial value left blank. You get the move, the reasoning and the SQL shape. You run it yourself to find out who it points at. Nothing is spoiled unless you choose to open a hint, and if you never open one, the first half of this post is still the most useful thing you can read before you start.
The skill this puzzle actually teaches is not writing SELECT statements. It is walking into a database you have never seen and working out where the bodies are buried.
First, read the room
The instinct when you open an unfamiliar database is to start querying immediately. Resist it for two minutes. The people who solve this quickly are not faster typists, they are the ones who spent the first two minutes working out the shape of the thing.
Three questions are worth answering before you write a single filter, and they apply to every database you will ever be handed.
Which table is the hub?
Almost every schema has one table that everything else points at. Find it and you have found your junction.
Here
person
Which tables are islands?
A table with no foreign keys cannot be joined to anything. If your starting information lives in one, your first move is not a JOIN at all.
Here
crime_scene_report, solution
What are the keys called?
Not everything is called id. One join here runs on a text membership id, another on a social security number.
Here
ssn, membership_id
Here is the whole thing. Click any table to see how you get out of it.
The crime scene, as a schemaprimary keyforeign key
person
The hub. Almost every trail passes through here, so when two things you need are not directly connected, this is nearly always the table you route through. Note that it points OUT to drivers_license and to income rather than being pointed at.
All nine tables and every field, taken from the live database, August 2026. The mystery itself is by Northwestern University Knight Lab.
Three details in that map cause almost every stall in the first ten minutes.
crime_scene_reporthas no keys at all, so you cannot join out of it. The bridge to the rest of the database is a street name buried in the description. Getting from prose to a row is not a trick here, it is the job.
personpoints out todrivers_license, not the other way round. Written backwards, the join is valid SQL that returns absolutely nothing.
Every date is an integer.20180115, not '2018-01-15'. Quote it and you are comparing a number to a string, which matches nothing and raises no error.
The investigation
Seven stages, each with three levels of help. Open only what you need, and stop at the first level that unsticks you. The queries show you the shape and leave the finding to you.
Nothing below gives you the answer. Every query has the crucial value left blank, marked <like this>, because the point is that you run it. Open a hint only when you are genuinely stuck, and stop at the first level that unsticks you.
01
Where do I even start?
You have a date, a city, and a crime type. Nothing else.
02
The report names two witnesses. Now what?
The description tells you where each witness lives, not who they are.
03
Reading the witness statements
You have person ids. The interviews are stored separately.
04
Following the gym trail
One transcript describes a membership: a status, and the first few characters of an id.
05
Following the vehicle trail
The other transcript gives you part of a number plate.
06
Crossing the two trails
You now have a set of names from the gym and a set from the plate.
07
If the check tells you it is not over
Submit your answer to the solution table and read what comes back. It may tell you the person you found was hired by somebody else.
When it returns nothing
The most demoralising thing in SQL is a query that runs perfectly and returns an empty table. No error, no clue, just nothing. Here are the five ways that happens in this puzzle, and what each one is really telling you.
✕
My date filter returns zero rows
date is declared as an integer here, not a date. The value is 20180115, so quoting it as '2018-01-15' compares a number to a string and matches nothing. Date functions will not work either.
WHEREdate=20180115
✕
My join to drivers_license returns nothing
The foreign key sits on person, pointing out to the licence, not the other way round. Written backwards the join is valid SQL and returns an empty set, which is why it feels like a data problem rather than a query problem.
JOINdrivers_licensedONd.id=p.license_id
✕
I know part of a value but LIKE finds nothing
LIKE without a wildcard is just a slower equals. A plate fragment could sit anywhere in the string, while a membership id prefix is anchored at the start, and those need different patterns.
LIKE'%H42W%'vsLIKE'48Z%'
✕
One person appears several times in my results
A gym member can check in on many days, so joining through check-ins multiplies rows. That is the join doing its job, not a duplicate bug.
FixAdd the date filter you were given, or wrap it in SELECT DISTINCT
✕
I found someone, but the solution check says no
Two things worth ruling out. Your filter may have been loose enough to catch more than one person, or you have found the right person at the wrong level. Read exactly what the check tells you before assuming the query was wrong.
FixRe-read the response, then narrow one filter at a time
The habit worth stealing
When a query returns nothing, delete your filters one at a time and rerun. The filter that brings rows back is the one that was wrong. It sounds obvious and almost nobody does it, reaching instead for a rewrite of the whole query. Bisecting a failed filter takes thirty seconds and works every time.
What this puzzle is quietly teaching you
Strip away the murder and look at what you actually did.
What you actually did
✓
You took a vague brief and turned it into a filter
WHERE
✓
You got from a sentence to a row when there was no key to follow
reading the data
✓
You chained joins through a bridge table because the two things you needed were never directly connected
multi-table JOIN
✓
You matched an identifier you only had part of
LIKE
✓
You crossed two independent lines of evidence to narrow a population to one
INTERSECT
✓
You grouped, then filtered on the count rather than on the rows
GROUP BY / HAVING
That is not puzzle SQL. That is Tuesday afternoon in a data job. The murder is a delivery mechanism for a realistic sequence of analytical moves, which is why the thing has outlasted every "learn SQL in 10 minutes" tutorial published the same year.
It is also why the format works. Nobody abandons a query halfway through when they actually want to know the answer.
What it does not cover, and what to do next
The mystery is one puzzle. It ends the moment you solve it, and it was never trying to be a course.
What you will not meet along the way: GROUP BY in anger beyond the final stage, HAVING as a habit rather than a one-off, subqueries and CTEs for structuring anything complicated, window functions for ranking and running totals, or any sense of the order a database actually executes your clauses in. Those are the things that separate someone who can follow a trail from someone who can answer a question nobody has asked yet.
If you enjoyed the format and want the next thing, we wrote an honest comparison of the free SQL games and learning resources worth your time, including several we did not make and one we did. If you want to go straight at the gaps above, JOINs and window functions are the two that unlock the most, in that order.
And if what appealed here was specifically the shape of it, a case, a database, a question worth answering, that is the thing QueryCase is built around. Same instinct, 54 cases deep instead of one.
Credit where it is due
The SQL Murder Mystery was made by Northwestern University Knight Lab, with components from Zi Chong Kao's Select Star SQL and a detective illustration by rambleron. The code is MIT licensed and the content is CC BY-SA 4.0. It is free, it needs no signup, and it is genuinely excellent. Go and play it properly before you read anyone's walkthrough, including this one.
SQL Murder Mystery: A Walkthrough That Doesn't Spoil It | QueryCase