Premium problem99. Monthly Survival Retention Curve

Hard Locked

users(user_id, signup_date) and activity(user_id, activity_date)

A user is churned once they have gone 30 consecutive days with no activity. The clock starts at signup, so somebody who signs up and never returns churns 30 days later. The churn moment is the end of that 30-day silence.

For each signup cohort month and month_number 0 to 6, return how many of the cohort had not yet churned by the last day of that relative month, and the percentage.

Return cohort_month as 'YYYY-MM', month_number, surviving_users and survival_pct rounded to two decimals, ordered by cohort then month number.

Unlike ordinary retention this curve can only fall. A user who comes back after churning does not un-churn, so each user needs a single churn date, which is the earliest 30-day silence rather than the last.

Tables

activity

user_id  activity_date
-------  -------------
1        2026-01-20
1        2026-02-10
1        2026-03-05
1        2026-04-01
1        2026-04-20
1        2026-05-10
1        2026-06-01
1        2026-06-20
... 9 more row(s)

users

user_id  signup_date
-------  -----------
1        2026-01-05
2        2026-01-10
3        2026-01-15
4        2026-01-20

Expected result

cohort_month  month_number  surviving_users  survival_pct
------------  ------------  ---------------  ------------
2026-01       0             4                100.00
2026-01       1             2                50.00
2026-01       2             1                25.00
2026-01       3             1                25.00
2026-01       4             1                25.00
2026-01       5             1                25.00
2026-01       6             1                25.00

Premium problem

This one's part of Premium. Unlock the full MySQL track plus every other premium problem on the site.

Write one SELECT query