SQL: SELECT and WHERE
An answer in 20 seconds
Kai asks: "How many gardens were defended yesterday in Europe?" Theo, the studio's data analyst, answers in 20 seconds by writing SQL, Structured Query Language, the language most databases and warehouses use for questions.
You won't need to type it here. You'll read it, which is most of the skill.
Theo's events table has one row per event and these columns:
event_name:garden_defended,level_shared...event_date: the day.player: a pseudonymous ID likep-91c2.region:eu,na,as...level_id: the player-made level, if there was one.
SELECT, FROM, WHERE
The PostgreSQL docs split a query into three parts: the select list, the columns to return; the table list, after FROM; and an optional WHERE condition. Only rows where the condition is true come back.
SELECT player, level_id FROM events WHERE event_name = 'level_shared';
Text goes in single quotes, numbers don't. AND, OR and NOT combine conditions.
Pick the query
Which query lists the levels shared in Europe?
- SELECT level_id FROM events WHERE event_name = 'level_shared' AND region = 'eu'
- SELECT level_id FROM events WHERE event_name = 'level_shared' OR region = 'eu'
- SELECT level_id FROM events WHERE region = 'eu'
Show the answer
SELECT level_id FROM events WHERE event_name = 'level_shared' AND region = 'eu'
AND keeps rows where both are true. OR would also return every other event from Europe, and the last query has no event name at all.
Counting
Often the answer is a number, not a list. COUNT(*) counts the rows:
SELECT COUNT(*) FROM events WHERE event_name = 'garden_defended' AND region = 'eu' AND event_date = '2026-10-10';
One row comes back: 48,210. COUNT(level_id) would count only the rows where level_id isn't empty.
Sorting and the first few
ORDER BY sorts the result: smallest first by default, or largest first with DESC. LIMIT 10 returns at most 10 rows.
The PostgreSQL docs warn: without ORDER BY, rows come back in an unspecified order that must not be relied on. With LIMIT but no ORDER BY, you get an unpredictable set of rows.
Quick check
Without ORDER BY, a query always returns rows in the order they were added.
- True
- False
Show the answer
False
The order is unspecified and depends on how the database reads the data, so it can change between runs. Only ORDER BY guarantees an order.
The trap called NULL
A NULL is a missing value. Gardens defended on the studio's own maps have no level_id, so it is NULL.
The PostgreSQL docs explain: comparing anything with NULL gives NULL, meaning "unknown", not true or false. Even NULL = NULL is unknown. So WHERE level_id = NULL never matches a row.
Use IS NULL and IS NOT NULL instead.
Bug hunt
1SELECT COUNT(*)2FROM events3WHERE event_name =4 'garden_defended'5 AND level_id = NULL;
Theo wants gardens defended on the studio's own maps, which have no level_id. The answer is always 0. Which line is the bug?
- Line 5
- Line 1
- Line 3
Show the answer
Line 5
level_id = NULL is never true, because a comparison with NULL is unknown. Line 5 should say level_id IS NULL.
One number per day
One count answers one question. Kai wants a count for every day of the week, and Remy wants to link shares to the levels they came from.
Bolt says: Next: GROUP BY and JOIN.
Fact-checked 11 October 2026
- PostgreSQL: Querying a table postgresql.org
- PostgreSQL: Sorting rows (ORDER BY) postgresql.org
- PostgreSQL: LIMIT and OFFSET postgresql.org
- PostgreSQL: Comparison functions and operators (NULL) postgresql.org