Well-Attended Gym Classes
A gym wants to know which group classes have a real following. A class counts as popular when at least 4 different members have booked it. A member who books the same class many times still counts only once.
Return class_name and member_count (the number of different members who booked that class) for every popular class, one row per class, in any order. If no class reaches 4 members, return no rows.
Tables
class_bookings — One row per booking of a group class. The same member can book the same class on many dates.
| Column | Type | Description |
|---|---|---|
booking_id (key) | INTEGER | Unique booking id |
class_name | TEXT | Name of the class, for example Spin or Pilates |
member_id | INTEGER | Member who made the booking |
class_date | TEXT | Date of the session booked, 'YYYY-MM-DD' |
Example
class_bookings
| booking_id | class_name | member_id | class_date |
|---|---|---|---|
| 1 | Spin | 11 | 2026-05-04 |
| 2 | Spin | 12 | 2026-05-04 |
| 3 | Spin | 11 | 2026-05-11 |
| 4 | Spin | 13 | 2026-05-11 |
| 5 | Spin | 11 | 2026-05-18 |
| 6 | Pilates | 12 | 2026-05-05 |
| 7 | Pilates | 14 | 2026-05-05 |
| 8 | Pilates | 15 | 2026-05-06 |
| 9 | Pilates | 11 | 2026-05-12 |
| 10 | Boxing | 16 | 2026-05-07 |
| 11 | Boxing | 17 | 2026-05-07 |
Expected output
| class_name | member_count |
|---|---|
| Pilates | 4 |
Rows may be returned in any order. Your query also runs against hidden datasets with tricky edge cases.
SQL Path · Aggregation & Grouping · problem 13 of 70 · SQLite
The idea
Group the bookings by class_name so that each class becomes one row. Inside each group, COUNT(DISTINCT member_id) counts different members, ignoring how often each one booked. A plain COUNT(*) would count bookings, so one dedicated regular could make a class look busy.
The popularity rule is a condition on that aggregate, so it belongs in HAVING, which is evaluated after grouping. "At least 4" means >= 4. Using the same COUNT(DISTINCT ...) in both the SELECT list and HAVING keeps the displayed number and the filter consistent.
The alternative first removes repeat bookings with SELECT DISTINCT class_name, member_id, leaving one row per class-member pair. After that, a plain COUNT(*) per class is already a count of different members. This two-step version is handy in databases where COUNT(DISTINCT) is slow or when you need the deduplicated pairs for other calculations.
Solution
SELECT class_name,
COUNT(DISTINCT member_id) AS member_count
FROM class_bookings
GROUP BY class_name
HAVING COUNT(DISTINCT member_id) >= 4;
Another way
SELECT class_name,
COUNT(*) AS member_count
FROM (
SELECT DISTINCT class_name, member_id
FROM class_bookings
) AS attendees
GROUP BY class_name
HAVING COUNT(*) >= 4;
Why common answers fail
Counts bookings instead of different members, so one regular booking a class four times makes it look popular.
SELECT class_name, COUNT(*) AS member_count FROM class_bookings GROUP BY class_name HAVING COUNT(*) >= 4;
Uses > 4, so a class with exactly 4 members is left out although "at least 4" includes it.
SELECT class_name, COUNT(DISTINCT member_id) AS member_count FROM class_bookings GROUP BY class_name HAVING COUNT(DISTINCT member_id) > 4;
Shows distinct members but filters on the number of bookings, so repeat bookings still push small classes over the bar.
SELECT class_name, COUNT(DISTINCT member_id) AS member_count FROM class_bookings GROUP BY class_name HAVING COUNT(*) >= 4;
What the interviewer is checking
Tests GROUP BY with HAVING and whether you notice that rows (bookings) are not the same as entities (members).
Mistakes to avoid
- Counting bookings instead of distinct members.
- Using > instead of >= for "at least".
- Filtering with a different expression from the one displayed.
Follow-ups to expect
- Rank classes by member count. (ORDER BY member_count DESC or RANK() OVER)
- Popular classes per month. (GROUP BY class_name, strftime('%Y-%m', class_date))
- Members who booked every class. (relational division: HAVING COUNT(DISTINCT class_name) = total classes)
In real work
Product teams measure feature reach by distinct users rather than events, the same distinction between bookings and members.