runtime
53 / 88

lesson 53 Advanced product analysis · advanced

Cohorts & exact-day retention

Measure whether users return on a specific day after joining.

the idea

A cohort groups users by when they started; retention asks what share came back later. Exact-day retention checks activity on one specific day (signup date + 7 for D7). Only include cohorts that are mature: their measurement day must fall before the data ends.

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.

users9 columns · 11,348 rows
user_idnumber · unique idaccount_idnumber · links to accountsfull_nametextemailtextroletextsignup_sourcetextreferred_by_user_idnumber · links to userscreated_atdate & timedeactivated_attext
11Omar Jacksonomar.jackson@ironcapital1.exampleownerworkspace_creatorNULL2024-01-14 18:52:14NULL
21Imani Kangimani.kang@ironcapital1.exampleadmininvitationNULL2024-01-24 03:43:14NULL
31Chloe Mitchellchloe.mitchell@ironcapital1.exampleadmininvitationNULL2024-02-02 21:34:25NULL
41Jaya Carterjaya.carter@ironcapital1.examplememberdomain_joinNULL2024-03-31 03:39:32NULL
51Zoe Turnerzoe.turner@ironcapital1.examplememberdomain_joinNULL2024-02-12 02:53:31NULL
62Esther Smithesther.smith@vectordata2.exampleownerworkspace_creatorNULL2024-01-15 13:21:52NULL
user_idnumber · unique id
1
account_idnumber · links to accounts
1
full_nametext
Omar Jackson
emailtext
omar.jackson@ironcapital1.example
roletext
owner
signup_sourcetext
workspace_creator
referred_by_user_idnumber · links to users
NULL
created_atdate & time
2024-01-14 18:52:14
deactivated_attext
NULL
user_idnumber · unique id
2
account_idnumber · links to accounts
1
full_nametext
Imani Kang
emailtext
imani.kang@ironcapital1.example
roletext
admin
signup_sourcetext
invitation
referred_by_user_idnumber · links to users
NULL
created_atdate & time
2024-01-24 03:43:14
deactivated_attext
NULL
user_idnumber · unique id
3
account_idnumber · links to accounts
1
full_nametext
Chloe Mitchell
emailtext
chloe.mitchell@ironcapital1.example
roletext
admin
signup_sourcetext
invitation
referred_by_user_idnumber · links to users
NULL
created_atdate & time
2024-02-02 21:34:25
deactivated_attext
NULL
user_idnumber · unique id
4
account_idnumber · links to accounts
1
full_nametext
Jaya Carter
emailtext
jaya.carter@ironcapital1.example
roletext
member
signup_sourcetext
domain_join
referred_by_user_idnumber · links to users
NULL
created_atdate & time
2024-03-31 03:39:32
deactivated_attext
NULL
user_idnumber · unique id
5
account_idnumber · links to accounts
1
full_nametext
Zoe Turner
emailtext
zoe.turner@ironcapital1.example
roletext
member
signup_sourcetext
domain_join
referred_by_user_idnumber · links to users
NULL
created_atdate & time
2024-02-12 02:53:31
deactivated_attext
NULL
user_idnumber · unique id
6
account_idnumber · links to accounts
2
full_nametext
Esther Smith
emailtext
esther.smith@vectordata2.example
roletext
owner
signup_sourcetext
workspace_creator
referred_by_user_idnumber · links to users
NULL
created_atdate & time
2024-01-15 13:21:52
deactivated_attext
NULL

first 6 of 11,348 rows · your queries use all of them

events8 columns · 135,428 rows
delivery_idnumber · unique idevent_idtextuser_idnumber · links to usersaccount_idnumber · links to accountssession_idnumber · links to sessionsevent_nametextoccurred_atdate & timereceived_atdate & time
1evt_0000001111user_signed_up2024-01-14 18:52:142024-01-14 18:52:33
2evt_0000002111onboarding_started2024-01-14 18:52:512024-01-14 18:53:06
3evt_00000846232user_signed_up2024-01-15 13:21:522024-01-15 13:22:00
4evt_00000856232onboarding_started2024-01-15 13:22:052024-01-15 13:22:16
5evt_00000866232onboarding_completed2024-01-15 13:23:522024-01-15 13:24:12
6evt_0000019119search_performed2024-01-17 20:56:552024-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.

  1. Size each signup month. Run this. cohort_month groups users by when they joined—the denominator before you measure who came back.the pattern

    example.sql
    SELECT substr(created_at, 1, 7) AS cohort_month, COUNT(*) AS signups
    FROM users
    GROUP BY cohort_month;
  2. Check one user on day 7. Run this. d7 is signup plus seven days; events_on_d7 counts activity on that calendar day only.

    step-2.sql
    SELECT
      u.user_id,
      date(u.created_at) AS signup_day,
      date(u.created_at, '+7 days') AS d7,
      COUNT(e.delivery_id) AS events_on_d7
    FROM users u
    LEFT JOIN events e
      ON e.user_id = u.user_id
      AND date(e.occurred_at) = date(u.created_at, '+7 days')
    WHERE u.user_id BETWEEN 9000 AND 9010
    GROUP BY u.user_id;
  3. See who is D7-measurable. Run this. d7_observable counts signups whose seventh day already passed in the data—recent signups stay out until you can see that day.

    step-3.sql
    SELECT
      substr(created_at, 1, 7) AS cohort_month,
      COUNT(*) AS signups,
      SUM(date(created_at, '+7 days') <= '2025-06-30') AS d7_observable
    FROM users
    WHERE created_at >= '2025-05-01'
    GROUP BY cohort_month;

common mistake

Users who signed up on 2025-06-28 cannot have D7 activity in data that ends on 2025-06-30. Including them makes the newest cohort look worse.

challenge 1

For users created from 2025-01-01 whose D7 day (signup date + 7 days) is no later than 2025-06-30, return cohort_month (YYYY-MM of created_at), cohort_size, retained_d7 (users with any event on their D7 day) and retention_pct (0–100, 2 decimals).

what to return

Columns
cohort_monthcohort_sizeretained_d7retention_pct in this order
Rows
any order
challenge-1.sql
 
To master this lesson, solve both challenges without hints and pass the concept check. 3 of 3 to go.
Cohorts & exact-day retention — Advanced product analysis · Runtime