Count Users Whose First Daily Event Is App Launch
SnapchatData Scientist · Technical ScreenLast updated
Write a PostgreSQL query to identify each user's first event per calendar day and aggregate the distinct user count by operating system and device when that first event is an app launch. Tests window functions, tie-breaking logic, and multi-dimensional grouping.
Problem Statement
You are given an event telemetry table for a mobile application. For each calendar day, a user can trigger multiple events across different devices.
Write a PostgreSQL query to find the number of distinct users whose first event of the day was an 'app_launch'. Report the results grouped by the event date, operating system (os), and device_model associated with that initial event.
Table Schema: user_events
| Column Name | Data Type | Description |
|---|---|---|
event_id | BIGINT | Unique identifier for the event |
user_id | INT | Unique identifier for the user |
event_name | VARCHAR | Name of the event (e.g., 'app_launch', 'send_chat', 'open_camera') |
event_timestamp | TIMESTAMP | Timestamp when the event occurred |
os | VARCHAR | Operating system (e.g., 'iOS', 'Android') |
device_model | VARCHAR | Hardware model (e.g., 'iPhone 15', 'Pixel 8') |
Requirements
- A calendar day is defined by the date portion of
event_timestamp(event_timestamp::DATE). - A user's "first event of the day" is the event with the earliest
event_timestampfor that user on that calendar day. If multiple events share the exact same earliest timestamp for a user on that day, break the tie deterministically using the smallestevent_id. - Only include days, operating systems, and device models where there is at least one qualifying user.
- Output columns:
event_date,os,device_model,user_count. - Sort output by
event_date ASC,os ASC,device_model ASC.
Example
Input (user_events)
+----------+---------+-------------+---------------------+---------+--------------+
| event_id | user_id | event_name | event_timestamp | os | device_model |
+----------+---------+-------------+---------------------+---------+--------------+
| 101 | 1 | app_launch | 2024-03-01 08:00:00 | iOS | iPhone 15 |
| 102 | 1 | send_chat | 2024-03-01 08:05:00 | iOS | iPhone 15 |
| 103 | 2 | open_camera | 2024-03-01 09:00:00 | Android | Pixel 8 |
| 104 | 2 | app_launch | 2024-03-01 09:10:00 | Android | Pixel 8 |
| 105 | 3 | app_launch | 2024-03-01 07:30:00 | iOS | iPhone 15 |
| 106 | 3 | app_launch | 2024-03-02 10:00:00 | iOS | iPhone 15 |
+----------+---------+-------------+---------------------+---------+--------------+
Output
+------------+-----+--------------+------------+
| event_date | os | device_model | user_count |
+------------+-----+--------------+------------+
| 2024-03-01 | iOS | iPhone 15 | 2 |
| 2024-03-02 | iOS | iPhone 15 | 1 |
+------------+-----+--------------+------------+
Explanation:
- On
2024-03-01:- User 1's first event is
app_launch(iOS, iPhone 15). - User 2's first event is
open_camera(excluded). - User 3's first event is
app_launch(iOS, iPhone 15). - Distinct users with
app_launchas their first event oniPhone 15: 2 (User 1 and User 3).
- User 1's first event is
- On
2024-03-02:- User 3's first event is
app_launch(iOS, iPhone 15). - Count: 1.
- User 3's first event is
Hints
Hint 1
Use ROW_NUMBER() partitioned by user_id and the casted calendar date, ordered by event_timestamp and event_id.
Hint 2
Filter for rows where the row number is 1 and the event_name equals 'app_launch' before performing the final aggregation.
Hint 3
Group by the date, os, and device_model columns, and compute COUNT(DISTINCT user_id) or COUNT(user_id).
Follow-up questions
- How would you optimize this query if `user_events` contains billions of rows partitioned daily?
- If a user can use both an iPhone and an Android on the same day, how would you ensure the first event across all devices is chosen versus the first event per device?
- How does PostgreSQL's `DISTINCT ON (user_id, event_date)` compare in performance and syntax to `ROW_NUMBER()` for this specific use case?
Solution walkthrough is for members
Get the full walkthrough with reference code and complexity analysis, plus Kitty Coach at 300 messages a day. Hints, the code runner and community answers stay free.