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

Expected result on the shared dataset
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;
Expected result on the shared dataset
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;
Expected result on the shared dataset
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;
Expected result on the shared dataset
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;
Expected result on the shared dataset
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;
Expected result on the shared dataset
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;
Expected result on the shared dataset
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;
Expected result on the shared dataset
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;
Expected result on the shared dataset
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;
Expected result on the shared dataset
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;
Expected result on the shared dataset
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;
Expected result on the shared dataset
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;
Expected result on the shared dataset
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