AdvancedWindow Functions

Calculate customer retention cohorts

The query

SQL
WITH cohorts AS (
  SELECT
    cust_id,
    DATE_TRUNC('month', MIN(order_date))::DATE AS cohort_month
  FROM orders
  GROUP BY cust_id
),
cohort_activity AS (
  SELECT
    c.cust_id,
    c.cohort_month,
    DATE_TRUNC('month', o.order_date)::DATE AS activity_month,
    EXTRACT(YEAR FROM AGE(
      DATE_TRUNC('month', o.order_date),
      c.cohort_month
    )) * 12 +
    EXTRACT(MONTH FROM AGE(
      DATE_TRUNC('month', o.order_date),
      c.cohort_month
    )) AS months_since_first_order
  FROM cohorts c
  JOIN orders o ON c.cust_id = o.cust_id
)
SELECT
  cohort_month,
  months_since_first_order AS period,
  COUNT(DISTINCT cust_id) AS retained_customers
FROM cohort_activity
GROUP BY cohort_month, months_since_first_order
ORDER BY cohort_month, period;
Tested against PostgreSQL 16

Note

Cohort retention analysis: tracks how many customers from each signup month remain active over time.

Tables referenced