iOS Sessions by Device Type
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
Problem
Each session in user_sessions records only a device_id, while the device's type and operating system are stored in devices. Count the sessions that came from mobile devices, broken down by operating system.
iOS engagement, device by device.
Tables
user_sessions
Columns: session_id INTEGER, user_id INTEGER, device_id INTEGER, session_start TEXT, session_duration_sec INTEGER, pages_viewed INTEGER
| session_id | user_id | device_id | session_start | session_duration_sec | pages_viewed |
|---|---|---|---|---|---|
| 7061 | 197 | 230 | 2026-02-02 01:00:00 | 53 | 3 |
| 7122 | 294 | 259 | 2026-03-03 02:00:00 | 76 | 6 |
| 7183 | 391 | 288 | 2026-04-04 03:00:00 | 99 | 9 |
| 7244 | 488 | 317 | 2026-05-05 04:00:00 | 122 | 12 |
| 7305 | 585 | 346 | 2026-06-06 05:00:00 | 145 | 15 |
| 7366 | 682 | 375 | 2026-07-07 06:00:00 | 168 | 18 |
| 7427 | 779 | 404 | 2026-08-08 07:00:00 | 191 | 21 |
| 7488 | 876 | NULL | 2026-09-09 08:00:00 | 214 | 24 |
| 7549 | 973 | 462 | 2026-01-10 09:00:00 | 237 | 27 |
| 7610 | 1070 | 491 | 2026-02-11 10:00:00 | 260 | 30 |
devices
Columns: device_id INTEGER, device_type TEXT, os_name TEXT, os_version TEXT, browser TEXT
| device_id | device_type | os_name | os_version | browser |
|---|---|---|---|---|
| 201 | desktop | Android | 15.1 | Chrome |
| 230 | tablet | Windows | 16.2 | Firefox |
| 259 | smart_tv | macOS | 17.0 | Edge |
| 288 | wearable | Linux | 11 | Opera |
| 317 | mobile | tvOS | 12 | Samsung Internet |
| 346 | desktop | watchOS | 13 | NULL |
| 375 | tablet | iOS | 10.0.19041 | Safari |
| 404 | smart_tv | Android | 14.1 | Chrome |
| 433 | wearable | Windows | NULL | Firefox |
| 462 | mobile | macOS | 14.0 | Edge |
Expected output
| os_name | session_count |
|---|---|
| Android | 6 |
| Linux | 5 |
| Windows | 5 |
| iOS | 4 |
| macOS | 5 |
Worked solution and explanation
This is a fact-to-dimension filter dressed up as a usage report. The thing you count, sessions, lives in user_sessions. The attribute that decides which sessions qualify (device_type) and the label you report them under (os_name) both live in devices. Everyone sees that a join is needed. The trap is answering from the wrong side of it: count rows in devices and you get the mobile device population per operating system, not the sessions those devices started. A phone with four sessions collapses to one, and Android comes out at 3 when the seed holds 6.
Walk the grain
Step 1: Decide what one counted row is
The answer counts sessions, so every counted row must be a user_sessions row. devices is there to label and filter, never to be counted. Saying 'one row per session, tagged with its device' out loud before typing is most of the problem.
Step 2: Attach each session to its device
Join user_sessions to devices on device_id. device_id is unique in devices, so the join cannot multiply sessions. The sessions with a NULL device_id find no partner and drop out, which is right: nothing ties them to a mobile device.
Step 3: Keep mobile, then count per operating system
Put device_type = 'mobile' in WHERE so it removes rows before anything is counted, then group by os_name and count session_id. Seven operating systems come back, and together they account for the 35 mobile sessions.
SELECT d.os_name, COUNT(s.session_id) AS session_count
FROM user_sessions AS s
JOIN devices AS d ON s.device_id = d.device_id
WHERE d.device_type = 'mobile'
GROUP BY d.os_nameSELECT os_name, COUNT(*) AS session_count
FROM devices
WHERE device_type = 'mobile'
GROUP BY os_nameRuns cleanly and answers a different question: how many mobile devices each OS has.
- Counting devices
COUNT(*)overdevicesgives 20 mobile devices spread across the seven operating systems: 3 for Android, 2 for iOS. It never readsuser_sessions, so how often a device was used cannot show up.- Counting sessions
COUNT(s.session_id)after the join gives 35 sessions: 6 for Android, 4 for iOS. Each device contributes once per session it started, which is the number a usage report means.
Common follow-up questions
- How would you add each operating system's share of all mobile sessions next to its count? (Tests putting a grand total beside per-group counts without a second scan.)
- What changes if `devices` keeps one row per device per day, so `device_id` repeats? (Tests whether they check join-key uniqueness before trusting a count.)
- The report should now list every operating system, including ones with zero mobile sessions. What moves? (Tests where the mobile filter must sit once unmatched rows are kept.)