The Regulars

A hard SQL interview practice problem on DataDriven. Write the query and run it against a real database, with instant feedback.

Domain
SQL
Difficulty
hard
Seniority
L4
Asked in
Spotify

Problem

Our engagement team is separating one-time visitors from users who form a real habit. From the session log, find the users who were active in at least three separate calendar months.

Some users drift off after one visit. Find the ones who kept coming back.

Tables

user_sessions

Columns: session_id INTEGER, user_id INTEGER, device_id INTEGER, session_start TEXT, session_duration_sec INTEGER, pages_viewed INTEGER

user_sessions: 10 of 200 rows
session_iduser_iddevice_idsession_startsession_duration_secpages_viewed
70611972302026-02-02 01:00:00533
71222942592026-03-03 02:00:00766
71833912882026-04-04 03:00:00999
72444883172026-05-05 04:00:0012212
73055853462026-06-06 05:00:0014515
73666823752026-07-07 06:00:0016818
74277794042026-08-08 07:00:0019121
7488876NULL2026-09-09 08:00:0021424
75499734622026-01-10 09:00:0023727
761010704912026-02-11 10:00:0026030

Expected output

First 5 of 27 rows
user_id
100
197
294
391
488

Worked solution and explanation

What this really is

This is a retention question wearing an aggregation costume. Beneath 'active in at least three separate calendar months' sits one skill: can you count DISTINCT time buckets per user without letting raw session volume leak into the count? Anyone can write GROUP BY user_id with a HAVING threshold. What separates candidates is the DISTINCT inside COUNT. Drop it and a user with 50 sessions in a single January reads as active for 50 months, and your retention cohort fills up with people who showed up once and never returned.


Break down the requirements

Step 1: Extract the calendar month

Use strftime('%Y-%m', session_start) to normalize each timestamp to its year-month. Two sessions in the same month collapse to the same key, which is exactly what a 'calendar month' count needs.

Step 2: Count distinct months per user

COUNT(DISTINCT year_month) per user_id gives the number of separate calendar months each user was active. The DISTINCT is load-bearing: without it you count sessions, not months.

Step 3: Apply the threshold with HAVING

HAVING COUNT(DISTINCT ...) >= 3 keeps only users active in at least three months. Return user_id.


The solution

Distinct month count per user
SELECT user_id
FROM user_sessions
GROUP BY user_id
HAVING COUNT(DISTINCT strftime('%Y-%m', session_start)) >= 3

Common follow-up questions