February 2024 Signups

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

Problem

February signups from other years don't count: the lifecycle campaign being rebuilt targets only the users who joined in February 2025. Pull every column from users for each of them, whatever their account status.

One signup window. One cohort. Who joined the club?

Tables

users

Columns: user_id INTEGER, username TEXT, email TEXT, signup_date TEXT, account_status TEXT, age_bucket TEXT

users: 10 of 200 rows
user_idusernameemailsignup_dateaccount_statusage_bucket
100alicealice@example.com2025-02-02inactive25-34
197aaron42aaron42@example.com2026-03-03suspended35-44
294 ameliaamelia@example.com2024-04-04pending_verification45-54
391arjun arjun@example.com2025-05-05active55-64
488ava99ava99@example.com2026-06-06inactive65+
585andrew_kandrew_k@example.com2024-07-07suspendedNULL
682anikaanika@example.com2025-08-08 16:34:00pending_verification18-24
779aidenaiden@example.com2026-09-09 14:53:00active25-34
876aria_baria_b@example.com2024-10-10inactive35-44
973brianbrian@example.com2025-11-11suspended45-54

Expected output

First 5 of 9 rows
user_idusernameemailsignup_dateaccount_statusage_bucket
100alicealice@example.com2025-02-02inactive25-34
1264bilalbilal@example.com2025-02-14inactiveNULL
2428celineceline@example.com2025-02-26inactive55-64
3592evelynevelyn@example.com2025-02-10inactive35-44
4756gunnargunnar@example.com2025-02-22inactive18-24

Worked solution and explanation

Strip the marketing costume off and this is a filter for one month of one specific year. The whole problem is a single decision: how do you say that a row's signup_date sits in February 2025, not just in some February? Everyone writes the SELECT and the WHERE. What separates a clean answer from a buggy one is whether the year and the month are pinned together. Match the month alone and the cohort swallows every other year's February; bracket the days by hand and you risk the edge of the month. Either way the campaign mails the wrong list.

The trap: February is not a month, it is a year-month

The first reflex is strftime('%m', signup_date) = '02'. It reads like the question, and on this seed it is wrong: users holds February signups from other years too, and every one of them slips in. The second reflex is a hand-typed range, BETWEEN '2025-02-01' AND '2025-02-28'. That one makes you know the last day of the month, is inclusive on both ends, and quietly misses anything after midnight on the 28th once a time component appears. Stop guessing boundaries: derive a year-month label from each row and compare labels.

The month-only version
SELECT *
FROM users
WHERE strftime('%m', signup_date) = '02';

Matches February of every year, so other years' signups join the cohort.

Step 1: Reduce each signup_date to a year-month label

strftime('%Y-%m', signup_date) turns '2025-02-14' into '2025-02'. The year rides along with the month, so another year's February produces a different label, and month length never enters the picture.

Step 2: Compare the label to the target month

One equality, = '2025-02', keeps exactly the rows whose signup landed in that month of that year. It replaces both the month-only match and the two-sided range, along with the off-by-one risk the range carries.

Step 3: Return every column, every status

The campaign needs the full record, and no status filter applies: a suspended account that joined that month is still part of the cohort. SELECT * with nothing but the date predicate is the literal answer.

Canonical solution
SELECT *
FROM users
WHERE strftime('%Y-%m', signup_date) = '2025-02';

One equality on a derived year-month label: year and month pinned together, no month-length arithmetic.

Month only, or a guessed range
strftime('%m', signup_date) = '02' matches every year's February; BETWEEN '2025-02-01' AND '2025-02-28' makes you guess the last day and misses timestamped rows on it.
Equality on a year-month label
strftime('%Y-%m', signup_date) = '2025-02' pins the year, needs no month length, and has one clean boundary.

Common follow-up questions