users(user_id, signup_date) and activity(user_id, activity_date)
Build a long-form retention matrix. For every signup cohort month and every
month_number from 0 to 6, return the cohort size, how many of those users
were active in that relative calendar month, and the percentage.
Month 0 is the signup month itself, so it is not automatically 100 percent:
somebody can sign up and never do anything.
Return cohort_month as 'YYYY-MM', month_number, cohort_size,
retained_users and retention_pct rounded to two decimals, ordered by cohort
then month number. All seven rows appear for every cohort, including the ones whose
relative months lie in the future of the data.
The month numbers have to come from somewhere, since a cohort with no month-4 activity still needs its month-4 row.
Tables
activity
user_id activity_date
------- -------------
1 2026-01-06
1 2026-02-06
1 2026-03-06
2 2026-01-21
2 2026-03-21
4 2026-02-11
4 2026-02-12
users
user_id signup_date
------- -----------
1 2026-01-05
2 2026-01-20
3 2026-01-25
4 2026-02-10
Expected result
cohort_month month_number cohort_size retained_users retention_pct
------------ ------------ ----------- -------------- -------------
2026-01 0 3 2 66.67
2026-01 1 3 1 33.33
2026-01 2 3 2 66.67
2026-01 3 3 0 0.00
2026-01 4 3 0 0.00
2026-01 5 3 0 0.00
2026-01 6 3 0 0.00
2026-02 0 1 1 100.00
... 6 more row(s)