User Session Roster

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

Domain
SQL
Difficulty
medium
Seniority
L3
Asked in
Ripple

Problem

Our usernames were typed in by hand, so some carry stray spaces or capital letters, and we read each one as its trimmed, lowercase form. From users and user_sessions, build a roster of each user's cleaned name, account status, signup date and session start that keeps people who have never started a session, sorted by cleaned name and then by session start, earliest first.

Every user paired with their sessions, even users who never logged in

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

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 341 rows
usernameaccount_statussignup_datesession_start
aaron42suspended2026-03-032026-01-26 09:00:00
aaron42suspended2026-03-032026-02-02 01:00:00
abelactive2026-04-08NULL
aliceinactive2023-05-25NULL
ameliapending_verification2024-04-042026-02-27 10:00:00

Worked solution and explanation

What this roster is really asking

This is an outer join dressed up as a reporting chore, with a cleaning step riding on top. Everyone links users to user_sessions on user_id. What separates candidates is whether the people who never logged in survive. Reach for an inner join because the ask sounds like 'users and their sessions' and every session-less user disappears without an error. The headcount comes back short, and nobody notices until onboarding numbers stop adding up.

The second wrinkle is the name itself. The username column holds ' amelia' with a leading space, 'arjun ' with a trailing one, and 'Alice' next to 'alice'. Sorted raw, the padded and capitalized names land in the wrong place. The statement's rule of reading a name as its trimmed, lowercase form has to happen before the sort.


Building it

Step 1: Keep users on the preserved side

Start FROM users and LEFT JOIN user_sessions on user_id. A user with sessions fans out to one row per session. A user with none still yields exactly one row, with session_start filled in as NULL. That NULL row is the whole point of the question.

Step 2: Clean the name once, in the select list

Compute LOWER(TRIM(u.username)) AS username directly in the SELECT and sort on that alias. The cleaned value is written once, so the displayed name and the sort key can never disagree, and no intermediate step is needed for a query this flat.

Step 3: Sort by the cleaned name, then by session start

ORDER BY username, session_start walks the roster alphabetically by cleaned name and, within a name, from the earliest session onward. Because username resolves to the alias, 'Alice' and 'alice' both become 'alice' and their rows sort together by session_start, instead of splitting across the list.

Roster that keeps session-less users
SELECT
    LOWER(TRIM(u.username)) AS username,
    u.account_status,
    u.signup_date,
    s.session_start
FROM users u
LEFT JOIN user_sessions s
    ON u.user_id = s.user_id
ORDER BY username, session_start

One LEFT JOIN keeps every user; the cleaned username alias drives the sort.

Inner join
JOIN user_sessions keeps only users with at least one session. Every account that signed up and never came back is dropped, and the row count looks plausible enough that nobody checks.
Left join
LEFT JOIN user_sessions keeps every row of users. The never-engaged accounts show up once with a NULL session_start, which is exactly the population an onboarding or churn report exists to find.

Common follow-up questions