lesson 52 Advanced product analysis · advanced
Ordered conversion funnels
Count users who complete events in the required order.
the idea
An ordered funnel counts users who complete steps in sequence: each step must happen at or after the previous step. Find each user’s earliest qualifying time for step 1, then the earliest step-2 time at or after it, and so on. Users who skip a step stop there.
Dataset: Product / SaaS Analytics
The tables the challenges use, with their first 6 rows. Under each column name: the kind of value it holds, and which table it links to.
events8 columns · 135,428 rows
| delivery_idnumber · unique id | event_idtext | user_idnumber · links to users | account_idnumber · links to accounts | session_idnumber · links to sessions | event_nametext | occurred_atdate & time | received_atdate & time |
|---|---|---|---|---|---|---|---|
| 1 | evt_0000001 | 1 | 1 | 1 | user_signed_up | 2024-01-14 18:52:14 | 2024-01-14 18:52:33 |
| 2 | evt_0000002 | 1 | 1 | 1 | onboarding_started | 2024-01-14 18:52:51 | 2024-01-14 18:53:06 |
| 3 | evt_0000084 | 6 | 2 | 32 | user_signed_up | 2024-01-15 13:21:52 | 2024-01-15 13:22:00 |
| 4 | evt_0000085 | 6 | 2 | 32 | onboarding_started | 2024-01-15 13:22:05 | 2024-01-15 13:22:16 |
| 5 | evt_0000086 | 6 | 2 | 32 | onboarding_completed | 2024-01-15 13:23:52 | 2024-01-15 13:24:12 |
| 6 | evt_0000019 | 1 | 1 | 9 | search_performed | 2024-01-17 20:56:55 | 2024-01-17 20:56:59 |
- delivery_idnumber · unique id
- 1
- event_idtext
- evt_0000001
- user_idnumber · links to users
- 1
- account_idnumber · links to accounts
- 1
- session_idnumber · links to sessions
- 1
- event_nametext
- user_signed_up
- occurred_atdate & time
- 2024-01-14 18:52:14
- received_atdate & time
- 2024-01-14 18:52:33
- delivery_idnumber · unique id
- 2
- event_idtext
- evt_0000002
- user_idnumber · links to users
- 1
- account_idnumber · links to accounts
- 1
- session_idnumber · links to sessions
- 1
- event_nametext
- onboarding_started
- occurred_atdate & time
- 2024-01-14 18:52:51
- received_atdate & time
- 2024-01-14 18:53:06
- delivery_idnumber · unique id
- 3
- event_idtext
- evt_0000084
- user_idnumber · links to users
- 6
- account_idnumber · links to accounts
- 2
- session_idnumber · links to sessions
- 32
- event_nametext
- user_signed_up
- occurred_atdate & time
- 2024-01-15 13:21:52
- received_atdate & time
- 2024-01-15 13:22:00
- delivery_idnumber · unique id
- 4
- event_idtext
- evt_0000085
- user_idnumber · links to users
- 6
- account_idnumber · links to accounts
- 2
- session_idnumber · links to sessions
- 32
- event_nametext
- onboarding_started
- occurred_atdate & time
- 2024-01-15 13:22:05
- received_atdate & time
- 2024-01-15 13:22:16
- delivery_idnumber · unique id
- 5
- event_idtext
- evt_0000086
- user_idnumber · links to users
- 6
- account_idnumber · links to accounts
- 2
- session_idnumber · links to sessions
- 32
- event_nametext
- onboarding_completed
- occurred_atdate & time
- 2024-01-15 13:23:52
- received_atdate & time
- 2024-01-15 13:24:12
- delivery_idnumber · unique id
- 6
- event_idtext
- evt_0000019
- user_idnumber · links to users
- 1
- account_idnumber · links to accounts
- 1
- session_idnumber · links to sessions
- 9
- event_nametext
- search_performed
- occurred_atdate & time
- 2024-01-17 20:56:55
- received_atdate & time
- 2024-01-17 20:56:59
first 6 of 135,428 rows · your queries use all of them
worked example
Run these steps in order to see the idea before you write your own query. The step marked “the pattern” is what the challenges ask for. Running the example does not count toward progress.
Compare naive step counts. Run this. These totals count anyone who ever hit each step—they ignore whether onboarding came before the first project.the pattern
example.sqlSELECT event_name, COUNT(DISTINCT user_id) AS users FROM events WHERE event_name IN ('user_signed_up', 'onboarding_completed', 'project_created') GROUP BY event_name;
Walk one user’s timeline. Run this. User 100’s funnel events in time order—use this picture when you enforce signup → onboarding → project.
step-2.sqlSELECT user_id, event_name, occurred_at FROM events WHERE user_id = 100 AND event_name IN ('user_signed_up', 'onboarding_completed', 'project_created') ORDER BY occurred_at;
Pivot first time per step. Run this. CASE inside MIN gives each user’s earliest timestamp per event name; you still must require each step to come after the previous one.
step-3.sqlSELECT user_id, MIN(CASE WHEN event_name = 'user_signed_up' THEN occurred_at END) AS signed_up, MIN(CASE WHEN event_name = 'onboarding_completed' THEN occurred_at END) AS first_onboarding, MIN(CASE WHEN event_name = 'project_created' THEN occurred_at END) AS first_project FROM events WHERE user_id BETWEEN 100 AND 110 GROUP BY user_id;
common mistake
Counting users who ever did each event ignores order: a project created before onboarding would wrongly count as a completed funnel.