Average Sessions Per User

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
L3
Asked in
Google

Problem

The board deck needs a single engagement benchmark: the average number of sessions per user across the entire platform.

How often do users come 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 1 of 1 rows
avg_sessions_per_user
3.389830508474576

Worked solution and explanation

Why this problem exists in real interviews

The denominator is the whole question. user_sessions only contains users who actually had a session, so any average computed off this table is the engagement of active users, not the platform. If the board sees "4.2 sessions per user" and the inactive half of the user base is missing, that number is wrong for the deck it's going into.


Break down the requirements

Step 1: Count sessions per user

Inner query: COUNT(*) GROUP BY user_id. Every row in user_sessions is one session by construction (session_id is the grain), so COUNT(*) and COUNT(DISTINCT session_id) agree.

Step 2: Average the counts

Outer query averages those per-user counts. This is mathematically equivalent to COUNT(*) * 1.0 / COUNT(DISTINCT user_id) over the full table, and the one-pass form is dramatically cheaper at 200M rows.

Step 3: Confirm the denominator

If the deck wants average sessions across all registered users including zeros, you need a LEFT JOIN from users to user_sessions. The expected query treats inactive users as out of scope.


The solution

AVERAGE SESSIONS PER USER
SELECT AVG(session_count) AS avg_sessions_per_user
FROM (
  SELECT user_id, COUNT(*) AS session_count
  FROM user_sessions
  GROUP BY user_id
)

COMMON FOLLOW-UP QUESTIONS

Common follow-up questions

Subquery form (as written)
Two scans of intermediate rows: inner GROUP BY user_id builds a per-user count table, outer AVG reduces it. Readable, matches the spec exactly.
One-pass equivalent
SELECT COUNT(*) * 1.0 / COUNT(DISTINCT user_id) FROM user_sessions. Same answer, single aggregate, no intermediate materialization. At 200M rows the planner appreciates it.