Event schema
Fields the query expects
| Field | Type | Why it exists |
|---|---|---|
| timestamp_utc | Timestamp | Billing movement time. |
| account_id | Utf8 | Stable billing account identifier. |
| movement_type | Utf8 | new, expansion, contraction, churn, or reactivation. |
| mrr_change_usd | Float64 | Signed normalized recurring-revenue change. |
Copy the query
SELECT
date_trunc('month', timestamp_utc) AS month,
SUM(CASE
WHEN movement_type IN ('new', 'expansion', 'reactivation')
THEN mrr_change_usd ELSE 0.0
END) AS growth_mrr_usd,
-SUM(CASE
WHEN movement_type IN ('contraction', 'churn')
THEN mrr_change_usd ELSE 0.0
END) AS lost_mrr_usd,
SUM(mrr_change_usd) AS net_mrr_change_usd,
COUNT(DISTINCT account_id) AS accounts_changed
FROM billing_events
WHERE timestamp_utc >= now() - INTERVAL '12 months'
GROUP BY date_trunc('month', timestamp_utc)
ORDER BY month;This read-only query is planned and executed against an empty typed table with Apache DataFusion 45.2.0. We review the synthetic sample output separately. Check field types, thresholds, and counting rules against your own data. Read the testing methodology.
Query result
Recurring-revenue growth and loss
July remained positive, but contraction and churn consumed much more of gross growth.
| month | growth_mrr_usd | lost_mrr_usd | net_mrr_change_usd | accounts_changed |
|---|---|---|---|---|
| 2026-05 | 18,400 | 7,200 | 11,200 | 93 |
| 2026-06 | 22,100 | 9,800 | 12,300 | 117 |
| 2026-07 | 20,700 | 13,400 | 7,300 | 126 |
Synthetic example output. Run the query against your own event schema and thresholds before using it for operational decisions.
Reproduce the example
Download the sample data
The JSON bundle includes the event schema with field types, illustrative input rows, exact SQL, expected output, review notes, and engine version. The CSV contains the displayed result.
How the SQL works
- 1Positive movements combine new, expansion, and reactivation MRR.
- 2Lost MRR is negated for a readable positive bar while net change retains the signed total.
- 3Distinct account count helps distinguish a broad movement from one unusually large contract.
Edge cases to check
- Emit exactly one movement for a billing change or reconcile by provider event ID.
- Define whether annual contracts contribute normalized monthly value at booking or service time.
- Separate one-time fees and usage revenue from recurring revenue.
Recommended dashboard
- Stacked bars: growth_mrr_usd and lost_mrr_usd
- Trend: net_mrr_change_usd
- Table: largest account-level movements
Alert guidance
Review when lost MRR consumes an unusually large share of gross growth for a complete month.
Read alert setupSet up the events this query needs
Related instrumentation and guides
Define the source data
Event schemas for this analysis
Continue the analysis
Find features used before upgrade
Join feature events to upgrade events and rank behaviors that occur before paid conversion.
Open recipeMeasure churn and reactivation by cohort
Classify accounts as retained, churned, or reactivated from recurring meaningful product activity.
Open recipeCalculate trial-to-paid conversion
Measure how many trial accounts become paid customers within a fixed conversion window.
Open recipeRun it on your events
Create a table, adapt the fields, and save the result
Start free, send structured events, and use the query result as a chart, shared dashboard widget, or alert input.