Documentation Index
Fetch the complete documentation index at: https://cubed3-mintlify-d1b954ce-multistage.mintlify.app/llms.txt
Use this file to discover all available pages before exploring further.
Use case
We use multi-stage measures — measures that aggregate over already-aggregated data — for things like year-over-year comparisons, period-over-period comparisons, percent of total, ranks, and nested aggregates. We want those queries to be accelerated by pre-aggregations instead of falling back to the upstream data source. Multi-stage measures don’t slot into rollups the same way as plain additive measures: the values themselves cannot be re-aggregated from a rollup. Cube matches them by including the underlying base measures in the rollup and recomputing the multi-stage CTEs on top of the pre-aggregation at query time. This recipe shows the rules for building a rollup that matches multi-stage measures, plus patterns for the most common cases.How matching works
When a query references a multi-stage measure, Cube looks for a rollup that satisfies three conditions at once:- Base measures are included. Every measure referenced inside the
multi-stage
sqlexpression (directly or transitively) must be a member of the rollup. The multi-stage measure itself is not included inmeasures— only its building blocks. - All driving dimensions are included. Anything the multi-stage parameter
partitions by must be present in the rollup’s
dimensions:- For
group_by/add_group_by: every listed dimension. - For
reduce_by: every listed dimension, plus the dimensions the query groups by. - For
time_shift: the shiftedtime_dimensionand agranularityat least as fine as the shift interval and the query’s time granularity.
- For
- The base measures stay additive. The rollup can only be used if the
inner aggregation can be recomputed from the rollup rows. Use
additive types (
count,sum,min,max,count_distinct_approx) for the base. Avoidavgandcount_distinctas bases — decompose them intosum+countandcount_distinct_approxrespectively, the same way as for non-additive measures.
Pattern 1: time shift (year-over-year)
A time-shift measure compares the current period against a shifted one:revenue_by_status because:
- the base
revenueis in the rollup, statusis in the rollup, and- the rollup’s
created_atgranularity (day) is finer than the requestedmonth.
Pattern 2: percent of total with group_by
Percent-of-total uses group_by to fix the inner aggregation
to specific dimensions:
revenue grouped by country and product. Cube
re-aggregates it to country for the inner CTE, then divides at the outer
stage to produce the percentage. If the rollup omitted country, the inner
group_by: [country] could not be computed and the match would fail.
Pattern 3: nested aggregates with add_group_by
add_group_by computes an aggregate of an aggregate (e.g., the average of
per-customer averages). The rollup must include the add_group_by dimension:
region and selecting avg_customer_total matches:
Cube computes SUM(amount) per (region, customer_id) from the rollup, then
averages over customer_id per region in the outer CTE.
Pattern 4: ranking with reduce_by
reduce_by ranks rows within a group. The rollup must
include both the rank’s reduce_by dimension and the query’s grouping
dimensions:
product (from reduce_by) and country (from the query’s GROUP BY)
must be in the rollup so Cube can rank product within each country.
Common pitfalls
- Don’t list the multi-stage measure in
measures. Only its base measures belong in the rollup. Multi-stage measures are computed on top of the rollup, not stored in it. - Use additive bases.
avgandcount_distinctmake the rollup non-additive and disqualify it from multi-stage matching. Replace them withsum+count(and compute the average at query time) and withcount_distinct_approx. See the non-additive measures recipe for the full pattern. - Match granularity end-to-end. For
time_shift, the rollup’sgranularitymust be at least as fine as both the query’s granularity and the shift interval. - Include every
group_by/add_group_by/reduce_bydimension in the rollup, in addition to the dimensions the query itself groups by.
See also
- Multi-stage measures — concept and parameters
- Matching queries with pre-aggregations — general matching rules
- Accelerating non-additive measures — how to keep base measures additive
- Calculating share of total — an end-to-end multi-stage example