LEARN TO CODE | SQL | 02 RETRIEVING DATA
02 Retrieving data: challenges
Write, predict and debug retrieval queries, then combine your skills into a useful club shortlist.
START HERE | INDEPENDENT PRACTICE
Complete these tasks using the same Section 02 dataset. Predict the matching IDs or values before running your query. Then compare the result, explain any difference and tick the task after checking it.
Hints and solutions are optional reveals. Equivalent queries are valid if they satisfy the same conditions and required ordering. The completion ticks last only while this page is open.
Use this section’s expanded Clubs table. It is a separate retrieval dataset , not a migration of the Section 01 database. All examples use SQLite. The queries below read data without changing stored records.
Set up the shared dataset and run queries in VS Code
Create
sql_retrieval.py
in VS Code and paste this complete Python runner. With your Python interpreter and Python extension selected, click Run Python File. Standard Python installations normally include sqlite3.
Change only the SQL inside
query = """..."""
for each exercise. Keep setup_sql unchanged. Click Run again to rebuild the same in-memory dataset and print the new query result in the terminal. Python prints None for SQL NULL and quotes empty strings as ''. No data persists after the program ends.
import sqlite3
connection = sqlite3.connect(":memory:")
setup_sql = """
CREATE TABLE Clubs (
club_id INTEGER PRIMARY KEY,
club_name TEXT NOT NULL,
category TEXT NOT NULL,
capacity INTEGER NOT NULL,
room TEXT,
fee_cents INTEGER NOT NULL,
session_minutes INTEGER NOT NULL
);
INSERT INTO Clubs
(club_id, club_name, category, capacity, room, fee_cents, session_minutes)
VALUES
(1, 'Robotics', 'Technology', 12, 'AIR Lab', 1500, 90),
(2, 'Game Design', 'Technology', 16, 'Room 12', 0, 60),
(3, 'Art', 'Creative', 12, 'Studio', 800, 60),
(4, 'Film', 'Creative', 20, NULL, 1000, 90),
(5, 'Chess', 'Strategy', 16, 'Room 12', 0, 45),
(6, 'Coding', 'Technology', 20, 'AIR Lab', 0, 60),
(7, 'Drama', 'Creative', 24, NULL, 1200, 90),
(8, 'Robotics Junior', 'Technology', 10, '', 500, 45);
"""
query = """
SELECT club_id, club_name, category, capacity, room, fee_cents, session_minutes
FROM Clubs
ORDER BY club_id;
"""
try:
connection.executescript(setup_sql)
cursor = connection.execute(query)
print(" | ".join(column[0] for column in cursor.description))
for row in cursor.fetchall():
print(row)
except sqlite3.Error as error:
print("Database error:", error)
finally:
connection.close()
REFERENCE DATA
| club_id | club_name | category | capacity | room | fee_cents | session_minutes |
|---|---|---|---|---|---|---|
| 1 | Robotics | Technology | 12 | AIR Lab | 1500 | 90 |
| 2 | Game Design | Technology | 16 | Room 12 | 0 | 60 |
| 3 | Art | Creative | 12 | Studio | 800 | 60 |
| 4 | Film | Creative | 20 | NULL | 1000 | 90 |
| 5 | Chess | Strategy | 16 | Room 12 | 0 | 45 |
| 6 | Coding | Technology | 20 | AIR Lab | 0 | 60 |
| 7 | Drama | Creative | 24 | NULL | 1200 | 90 |
| 8 | Robotics Junior | Technology | 10 | (empty text) | 500 | 45 |
Money is stored as integer cents to avoid using binary floating point as the stored monetary amount. fee_cents = 0 means free, not unknown. Film and Drama have NULL rooms; Robotics Junior has an empty text room, deliberately included so you can compare the two situations.
CHALLENGE 01 | CHOOSE COLUMNS
Display each club’s name and capacity, in club_id order.
Need a hint?
Choose only two result columns; a sorting field need not be displayed.
Reveal a possible query and result
SELECT club_name, capacity FROM Clubs ORDER BY club_id;
| club_name | capacity |
|---|---|
| Robotics | 12 |
| Game Design | 16 |
| Art | 12 |
| Film | 20 |
| Chess | 16 |
| Coding | 20 |
| Drama | 24 |
| Robotics Junior | 10 |
The table retains all its fields. The query chooses its output columns.
CHALLENGE 02 | FILTER TWO CONDITIONS
Find Technology clubs with capacity at least 15. Show name and capacity.
Need a hint?
AND requires both comparisons.
Reveal a possible query and result
SELECT club_name, capacity FROM Clubs WHERE category = 'Technology' AND capacity >= 15 ORDER BY club_id;
| club_name | capacity |
|---|---|
| Game Design | 16 |
| Coding | 20 |
Game Design and Coding qualify.
CHALLENGE 03 | GROUP THE LOGIC
Find free clubs in either Technology or Strategy. Show their name and category.
Need a hint?
Group the alternatives before requiring a zero fee.
Reveal a possible query and result
SELECT club_name, category FROM Clubs WHERE (category = 'Technology' OR category = 'Strategy') AND fee_cents = 0 ORDER BY club_id;
| club_name | category |
|---|---|
| Game Design | Technology |
| Chess | Strategy |
| Coding | Technology |
Without suitable grouping, a free-only requirement can accidentally apply to only one branch.
CHALLENGE 04 | THE TOP THREE
Return the three largest-capacity clubs, breaking ties by ascending club_id.
Need a hint?
A deterministic ORDER BY comes before LIMIT.
Reveal a possible query and result
SELECT club_name, capacity FROM Clubs ORDER BY capacity DESC, club_id ASC LIMIT 3;
| club_name | capacity |
|---|---|
| Drama | 24 |
| Film | 20 |
| Coding | 20 |
Drama, Film and Coding are returned under this rule.
CHALLENGE 05 | THE NEXT PAGE
Return the second page of three clubs, in club_id order.
Need a hint?
Skip the first three rows.
Reveal a possible query and result
SELECT club_id, club_name FROM Clubs ORDER BY club_id LIMIT 3 OFFSET 3;
| club_id | club_name |
|---|---|
| 4 | Film |
| 5 | Chess |
| 6 | Coding |
The result contains IDs 4, 5 and 6. OFFSET is a row count to skip, not a page number.
CHALLENGE 06 | PATTERN MATCHING
Show names beginning with Robotics. Then explain why the shorter name also matches.
Need a hint?
Percent can match zero characters.
Reveal a possible query and result
SELECT club_name FROM Clubs WHERE club_name LIKE 'Robotics%' ORDER BY club_id;
| club_name |
|---|
| Robotics |
| Robotics Junior |
Robotics and Robotics Junior match. Percent does not require an extra character.
CHALLENGE 07 | LIST AND RANGE
Find Creative or Strategy clubs with capacity from 12 to 20 inclusive.
Need a hint?
Combine IN with BETWEEN.
Reveal a possible query and result
SELECT club_name, category, capacity FROM Clubs WHERE category IN ('Creative', 'Strategy') AND capacity BETWEEN 12 AND 20 ORDER BY club_id;
| club_name | category | capacity |
|---|---|---|
| Art | Creative | 12 |
| Film | Creative | 20 |
| Chess | Strategy | 16 |
Art, Film and Chess qualify. Both range boundaries are included.
CHALLENGE 08 | MISSING OR BLANK
Find clubs whose room is NULL or blank after ordinary-space trimming.
Need a hint?
NULL and empty text require different tests.
Reveal a possible query and result
SELECT club_name FROM Clubs WHERE room IS NULL OR trim(room) = '' ORDER BY club_id;
| club_name |
|---|
| Film |
| Drama |
| Robotics Junior |
Film, Drama and Robotics Junior qualify. IS NOT NULL alone would not remove a blank string.
CHALLENGE 09 | DISTINCT COMBINATIONS
Retrieve the distinct category and capacity pairs, sorted by both values.
Need a hint?
DISTINCT acts on the complete selected pair.
Reveal a possible query and result
SELECT DISTINCT category, capacity FROM Clubs ORDER BY category, capacity;
| category | capacity |
|---|---|
| Creative | 12 |
| Creative | 20 |
| Creative | 24 |
| Strategy | 16 |
| Technology | 10 |
| Technology | 12 |
| Technology | 16 |
| Technology | 20 |
Do not include club_id if you want repeated category–capacity pairs removed.
CHALLENGE 10 | CALCULATE A REPORT
For paid clubs, show name, fee in units and a label combining name and category. Sort highest fee first, then club_id.
Need a hint?
Use real division and SQLite text concatenation.
Reveal a possible query and result
SELECT club_name, fee_cents / 100.0 AS amount, club_name || ' (' || category || ')' AS label FROM Clubs WHERE fee_cents > 0 ORDER BY amount DESC, club_id;
| club_name | amount | label |
|---|---|---|
| Robotics | 15.0 | Robotics (Technology) |
| Drama | 12.0 | Drama (Creative) |
| Film | 10.0 | Film (Creative) |
| Art | 8.0 | Art (Creative) |
| Robotics Junior | 5.0 | Robotics Junior (Technology) |
The stored cents and names are unchanged. Free clubs are excluded by the explicit condition.
CHALLENGE 11 | DEBUG THE QUERY
Repair this request: select club names whose room is NULL (unassigned), order by descending capacity, and return two rows. Faulty query: SELECT club_name WHERE room = NULL FROM Clubs LIMIT 2 ORDER BY capacity DESC;
Need a hint?
Fix clause order and use the missing-value test.
Reveal a possible query and result
SELECT club_name FROM Clubs WHERE room IS NULL ORDER BY capacity DESC, club_id ASC LIMIT 2;
| club_name |
|---|
| Drama |
| Film |
The NULL rooms belong to Drama and Film. A blank string is not included.
CHALLENGE 12 | CAPSTONE: ADVERTISING SHORTLIST
Shortlist at most four Technology or Creative clubs with capacity at least 12 and an assigned, non-blank room. Display a club label, capacity, fee in units and four-session minutes. Sort free/cheaper clubs first, then larger capacity, then club_id.
Need a hint?
Separate eligibility, output calculations and ordering; filter the source fee field.
Reveal a possible query and result
SELECT club_name || ' (' || category || ')' AS club_label, capacity, fee_cents / 100.0 AS amount, session_minutes * 4 AS four_session_minutes FROM Clubs WHERE category IN ('Technology', 'Creative') AND capacity >= 12 AND room IS NOT NULL AND trim(room) <> '' ORDER BY fee_cents ASC, capacity DESC, club_id ASC LIMIT 4;
| club_label | capacity | amount | four_session_minutes |
|---|---|---|---|
| Coding (Technology) | 20 | 0.0 | 240 |
| Game Design (Technology) | 16 | 0.0 | 240 |
| Art (Creative) | 12 | 8.0 | 240 |
| Robotics (Technology) | 12 | 15.0 | 360 |
Coding, Game Design, Art and Robotics qualify in that order. Four is a maximum; this dataset happens to provide four matches.
STRETCH | EXPLAIN THE TRAPS
Explain each without running it first: why
LIMIT 3
alone does not mean “the biggest three”; why
room = NULL
does not find missing rooms; why
SELECT DISTINCT club_id, category
does not produce a unique category list; and why
1550 / 100
differs from
1550 / 100.0
in SQLite.
Reveal reasoning
A limit does not define order. Equality with NULL is not true. Unique IDs distinguish each selected pair. Integer division truncates when both operands are integers, while a real operand gives real division.
FINISH | CHECK YOUR UNDERSTANDING
Choose one filtering error, one ordering issue and one calculation issue you corrected. Explain each in your book, then rebuild the capstone query without the sample answer.
Next, joins will connect related tables and aggregate functions will summarise multiple records. The per-row arithmetic in this section is a foundation for those new ideas.
KEEP LEARNING
Previous page 03.1 INNER JOIN and LEFT JOIN
Reference: SQLite SELECT · SQLite expressions and filters