Daily Session and User Counts

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
Asked in
Meta

Problem

For each day in user_sessions, how many sessions started and how many different users were behind them? An analyst is laying the figures out as a daily engagement timeline, earliest day first.

Sessions and users, day by day.

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 182 rows
session_datetotal_sessionsunique_users
2023-01-0122
2023-01-0511
2023-01-0911
2024-12-1822
2025-11-0722

Worked solution and explanation

This is a grain question wearing a dashboard costume. Every row in user_sessions stamps an hour, and the dashboard wants a day, so the first job is throwing the clock time away. The second job is the one that separates candidates: two numbers at that grain, one counting every session and one counting each person once. Write the same count twice and the user column quietly equals the session column on any day someone comes back. On this data that day is 2026-06-15, where user 100 opens three overlapping sessions and a sloppy query claims 4 users instead of 2.

Getting to the query

Step 1: Bucket on the day, not the instant

session_start holds text like '2026-06-15 10:00:00'. Grouping on it as stored gives one bucket per start time, so the daily report becomes a list of sessions. DATE(session_start) drops the time and makes the calendar day the key, which is the thing the dashboard plots.

Step 2: Count sessions and people differently

Every row is one session, so COUNT(*) is the session total. People repeat across rows, so the user figure needs COUNT(DISTINCT user_id). Both sit in the same GROUP BY, which is why getting the grain right in step one fixes both metrics at once.

Step 3: Read it as a timeline

ORDER BY session_date puts the oldest day at the top. The date is unique per output row, so there is no tie left to break.

Daily sessions and unique users
SELECT
    DATE(session_start) AS session_date,
    COUNT(*) AS total_sessions,
    COUNT(DISTINCT user_id) AS unique_users
FROM user_sessions
GROUP BY DATE(session_start)
ORDER BY session_date

One pass over user_sessions, two counts at the day grain.

Counting rows twice
COUNT(*) for both columns. On 2026-06-15 this reports 4 sessions and 4 users, and the dashboard can never show anyone coming back.
Counting rows, then people
COUNT(*) beside COUNT(DISTINCT user_id). The same day reports 4 sessions from 2 users, and the gap is exactly the repeat visits the dashboard exists to show.

Common follow-up questions