Session Duration by Account Status

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
phData

Problem

Session length is logged per session in user_sessions while account status lives only on each person's users record, and a few sessions were never timed, so a blank duration is unknown rather than zero. An analyst checking whether account tier tracks engagement wants the average session duration in seconds for every account status.

Average session duration broken down by user account status

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 4 of 4 rows
account_statusavg_session_duration
active1278.0625
inactive1663.1707317073171
pending_verification1319.695652173913
suspended1355.3333333333333

Worked solution and explanation

This is a cross-table average dressed up as an engagement study. The metric, session_duration_sec, sits on user_sessions; the bucket, account_status, exists only on users. Everyone writes the join. What separates candidates is what they do with the sessions that were never timed: 17 of the 200 sessions carry a NULL duration, and the reflex to tidy them with COALESCE(session_duration_sec, 0) turns unknown sessions into zero-second ones. Every status average drops, by an amount that depends on how many untimed sessions that status happens to hold, so part of the tier gap the analyst is chasing becomes an artifact of missing data.

Getting to the answer

Step 1: Find where each piece lives

user_sessions has the duration and a user_id, but no status. No filter or projection over sessions alone can bucket them by tier, so you bring in users on user_id. Because user_id is unique in users, each session matches exactly one user: the join adds a column without multiplying sessions.

Step 2: Average sessions, not users

GROUP BY u.account_status with AVG(us.session_duration_sec) weights every session once. Averaging per user first and then across users gives a person with one session the same say as someone with eight, which answers a different question.

Step 3: Let the average skip untimed sessions

AVG drops NULLs from both the sum and the count, which is exactly what 'unknown, not zero' means. The correct handling of the blanks is to add nothing.

Average session duration per `account_status`
SELECT u.account_status, AVG(us.session_duration_sec) AS avg_session_duration
FROM users u
INNER
JOIN user_sessions us ON u.user_id = us.user_id
GROUP BY u.account_status
The defensive version that is wrong
SELECT u.account_status, AVG(COALESCE(us.session_duration_sec, 0)) AS avg_session_duration
FROM users u
JOIN user_sessions us ON u.user_id = us.user_id
GROUP BY u.account_status

COALESCE keeps the untimed sessions in the denominator at zero seconds, so every status average comes out low.

Common follow-up questions