SQL Example: Monthly Repeat Purchase Rate (Returning Customers / Total Customers)
Overview
This query calculates the repeat purchase rate (RPR) for a defined cohort of first-time customers — specifically, customers whose first order was exactly 12 months ago. It measures what percentage of those customers went on to make at least one additional purchase since their first order. This is useful for evaluating customer retention and long-term purchase behavior.
SQL Query
WITH
cohort_users AS (
SELECT
customer_id
FROM
orders_table
WHERE
order_revenue > 0
AND event_date >= toStartOfMonth (DATE_SUB(CURRENT_DATE(), INTERVAL 12 MONTH))
AND event_date < toStartOfMonth (DATE_SUB(CURRENT_DATE(), INTERVAL 11 MONTH))
AND is_new_customer
AND platform != 'amazon'
)
SELECT
uniq (cu.customer_id) as cohort_size,
uniqIf (cu.customer_id, customer_orders > 1) as repeat_customers,
ROUND(
uniqIf (cu.customer_id, customer_orders > 1) / uniq (cu.customer_id),
2
) as repeat_purchase_rate
FROM
cohort_users cu
LEFT JOIN (
SELECT
customer_id,
COUNT(*) as customer_orders
FROM
orders_table
WHERE
event_date >= toStartOfMonth (DATE_SUB(CURRENT_DATE(), INTERVAL 12 MONTH))
AND platform != 'amazon'
and order_revenue > 0
GROUP BY
customer_id
) ot USING (customer_id)
Tables and Metrics Used
Table
orders_table
(Orders Table)
Dimensions
event_date
customer_id
platform
is_new_customer
Measures
order_revenue
Customization Options
This query calculates the repeat purchase rate for a defined cohort of first-time customers — specifically, those whose first order occurred exactly 12 months ago. It measures how many of them went on to make at least one additional purchase over time. You can customize it in the following ways:
Change cohort month
- Adjust the
INTERVAL
in theDATE_SUB()
clauses to analyze a different cohort period (e.g. 6 months ago instead of 12).
Redefine "repeat" logic
- Replace
customer_orders > 1
with a different threshold if you want to define "repeat" more strictly (e.g. 3+ purchases).
Modify filters
- Adjust or remove filters like
platform != 'amazon'
ororder_revenue > 0
depending on your use case.
Updated about 5 hours ago