April and May Active Users
An easy SQL interview practice problem on DataDriven. Write the query and run it against a real database, with instant feedback.
- Domain
- SQL
- Difficulty
- easy
- Seniority
- L3
- Asked in
- ActiveCampaign
Problem
Return the user IDs with at least one session in April or May, each user listed once, lowest ID first. Read them from user_sessions, where a spring month counts in every year the log covers, not only the current one.
Spring cleaning for the user base. Who was actually around?
Tables
user_sessions
Columns: session_id INTEGER, user_id INTEGER, device_id INTEGER, session_start TEXT, session_duration_sec INTEGER, pages_viewed INTEGER
| session_id | user_id | device_id | session_start | session_duration_sec | pages_viewed |
|---|---|---|---|---|---|
| 7061 | 197 | 230 | 2026-02-02 01:00:00 | 53 | 3 |
| 7122 | 294 | 259 | 2026-03-03 02:00:00 | 76 | 6 |
| 7183 | 391 | 288 | 2026-04-04 03:00:00 | 99 | 9 |
| 7244 | 488 | 317 | 2026-05-05 04:00:00 | 122 | 12 |
| 7305 | 585 | 346 | 2026-06-06 05:00:00 | 145 | 15 |
| 7366 | 682 | 375 | 2026-07-07 06:00:00 | 168 | 18 |
| 7427 | 779 | 404 | 2026-08-08 07:00:00 | 191 | 21 |
| 7488 | 876 | NULL | 2026-09-09 08:00:00 | 214 | 24 |
| 7549 | 973 | 462 | 2026-01-10 09:00:00 | 237 | 27 |
| 7610 | 1070 | 491 | 2026-02-11 10:00:00 | 260 | 30 |
Expected output
| user_id |
|---|
| 100 |
| 197 |
| 294 |
| 391 |
| 488 |
Worked solution and explanation
This is a dedupe of a non-unique key wearing a growth-team costume. user_id is not a key in user_sessions: one person logs several sessions, and more than one of them can land in April or May. Anyone writes the month filter. What separates candidates is noticing that the filter returns sessions, not people. Skip the collapse and the user list repeats the same ID once per qualifying session, so every headcount and every campaign built on it fires more than once per person.
Read the grain before you filter
Step 1: Pull a numeric month out of session_start
session_start is text like '2026-04-04 03:00:00'. Extract its month and turn it into a number before comparing it to 4 and 5.
Step 2: Match the month, not one year's dates
Spring here means April and May in every year the log holds, and user_sessions spans 2023 through 2026. A single BETWEEN on one year's dates quietly drops the earlier springs and the users who were only active then.
Step 3: Collapse sessions into people
Project user_id alone and put DISTINCT on it. Selecting session_id or session_start next to it would make every row unique again and undo the collapse.
Step 4: Sort lowest ID first
ORDER BY user_id gives the order the list is read in. After the collapse every ID is unique, so there are no ties to settle.
The solution
SELECT DISTINCT user_id
FROM user_sessions
WHERE CAST(strftime('%m', session_start) AS INTEGER) IN (4, 5)
ORDER BY user_id- One row per session
SELECT user_idwith the month filter and noDISTINCT: a user with three spring sessions shows up three times.- One row per user
SELECT DISTINCT user_id: one row per person, whatever their session count.GROUP BY user_idreturns the same set, butDISTINCTstates the intent with less.
Common follow-up questions
- How many unique users were active each spring, one row per year? (Moves the year into the output grain, so the dedupe happens per year, not overall.)
- Return only the users active in both April and May of the same year. (Turns a membership filter into a per-user condition across two months.)
- How would you write the filter so a date-partitioned `user_sessions` can prune partitions? (Tests whether the candidate knows a function on the partition column defeats pruning.)
- What changes if `session_start` is stored in UTC and spring should follow each user's local time? (Probes converting time zones before extracting the month.)