User Devices

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

Problem

Sessions repeat heavily, so a user with fifty phone sessions still counts as engaging on one platform: each username and device type pair belongs in the result exactly once. From users, user_sessions and devices, list every device type each user with at least one session has engaged on, next to their username.

Desktop, mobile, tablet. What does each user actually use?

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

devices

Columns: device_id INTEGER, device_type TEXT, os_name TEXT, os_version TEXT, browser TEXT

devices: 10 of 200 rows
device_iddevice_typeos_nameos_versionbrowser
201desktopAndroid15.1Chrome
230tabletWindows16.2Firefox
259smart_tvmacOS17.0Edge
288wearableLinux11Opera
317mobiletvOS12Samsung Internet
346desktopwatchOS13NULL
375tabletiOS10.0.19041Safari
404smart_tvAndroid14.1Chrome
433wearableWindowsNULLFirefox
462mobilemacOS14.0Edge

Expected output

First 5 of 60 rows
usernamedevice_type
aaron42tablet
ameliasmart_tv
arjun wearable
ava99mobile
andrew_kdesktop

Worked solution and explanation

What this really is

This is a two-hop lookup through a bridge table that looks like a simple user report. The attribute you need, device_type, does not live on the session fact: user_sessions carries only device_id, so users joined to user_sessions alone can never answer it. Most candidates find the second hop to devices. The real split is what they do with the fan-out. Every session becomes a row, and with roughly 12.5 sessions per user spread over only four device types, the same (user, platform) pair comes back over and over. Skip the dedup and a result of about 60 pairs becomes tens of millions of rows, and any per-user platform count downstream measures session volume instead of platforms.


Getting there

Step 1: Hop from users to user_sessions

Inner-join on user_id. The inner join is the requirement: a user with no sessions has no platform to report, so dropping them is correct, not a side effect.

Step 2: Hop from user_sessions to devices

Join on device_id to reach device_type. This is the hop people skip when they assume the session row knows its platform. It does not, and the query will either fail or invent a column.

Step 3: Collapse the fan-out to one row per pair

Project only u.username and d.device_type, then SELECT DISTINCT over exactly those two columns. Project anything session-level, like session_id or session_start, and the dedup does nothing because every row is unique again.

Two hops, then collapse
SELECT DISTINCT u.username, d.device_type
FROM users u
JOIN user_sessions s ON u.user_id = s.user_id
JOIN devices d ON s.device_id = d.device_id
Join without dedup
One row per session: a user with 100 'mobile' sessions shows 'mobile' 100 times, and the output is as large as user_sessions itself.
Join with dedup
DISTINCT on (username, device_type) keeps one row per pair, so the result size tracks users times platforms, not session volume.

Common follow-up questions