Monthly cohort retention from a raw event log
From a single `events(user_id, event_name, occurred_at)` table, build a monthly cohort retention table. Rows are signup month, columns are months since signup, values are the percentage of that cohort still active. Two things separate a correct answer from a plausible one: months with no activity must appear as 0 rather than disappear, and months that have not happened yet must be blank rather than 0.
What you have to hand in
- Every user belongs to exactly one cohort.
- Month 0 is the signup month and shows 100% for every cohort.
- Inactive months inside a cohort's lifetime show 0, not blank.
- Future months show blank, not 0.
- Cohort size is visible alongside the percentages.
The checklist, published before you start
- Cohorts are assigned correctly
Each entity belongs to exactly one cohort, derived from its first qualifying event.
- Entities appear in several cohorts, or cohorts are assigned from an arbitrary event.
- First-event logic is present but mis-handles ties or timezone boundaries.
- Each entity is in exactly one cohort, based on its first event.
- Correct, and the tie/boundary rule is stated explicitly.
- Period offsets are correct
Month 0 means the signup period; offsets count from the cohort's own start, not from a fixed date.
- Offsets are calendar periods rather than periods since signup.
- Offsets are relative but off by one, or inconsistent across cohorts.
- Offsets are correct and consistent.
- Correct, with the month-0 convention documented.
- No missing periods
Periods with zero activity appear as zero rather than vanishing from the output.
- Zero-activity periods are missing, making retention look better than it is.
- Some periods filled, others missing.
- All periods present within each cohort's lifetime.
- All periods present, and periods after the data ends are correctly excluded rather than shown as zero.
- The denominator is right
Retention is measured against the cohort's own size, not the total population.
- Divides by the wrong population.
- Correct denominator but not held constant across periods.
- Cohort size used consistently as the denominator.
- Correct, with the cohort size shown alongside the percentages so a small cohort is visible.
- A colleague could maintain it
The query is decomposed into named steps that map onto the analysis.
- A single opaque query.
- Partially decomposed.
- Named CTEs matching the analytical steps.
- Structure makes the method obvious without the write-up.
The skills a pass would prove
- Cohort analysisBuild a cohort retention table from a raw event log
- Date truncation and time seriesProduce a time series with no missing periods, including days with zero activity
- Ranking functionsReturn the top N rows per group with the right tie-breaking behaviour
- Common table expressionsDecompose a complex query into named CTEs that each answer one clear question
This brief is part of the SQL & Data Analysis course
Starting it starts the course: every skill above, in the order they depend on each other, with this brief at the end as the thing you hand in — marked against the checklist you have just read and nothing else.
Start the SQL & Data Analysis course