AQL in 30 minutes
This is the fast-track tour. Read top to bottom in about 5 minutes for a working mental model; click into any Learn page when you want the full treatment.
For the slow path with one concept per page, see the learning roadmap on the AQL overview.
Prerequisites
AQL works against AML data models. You'll need a dataset with a few models and relationships defined. Quick example:
Model users { dimension id {} dimension gender {} dimension age {} }
Model countries { dimension id {} dimension name {} }
Dataset e_commerce {
models: [users, countries]
relationships: [relationship(users.country_id > countries.id, true)]
}
1. The pipe operator
| chains operations left-to-right. x | f(args) is the same as f(x, args).
users | avg(users.age) // average age of all users
2. Filtering
Two filters:
filter()narrows a table (like SQLWHERE).where()narrows a metric (the filter rides with the aggregation).
// Drop rows before aggregating
users | filter(users.gender == 'Female') | count(users.id)
// Bake the filter into a metric
count(users.id) | where(users.gender == 'Female')
3. Grouping and aggregation
group() collapses by a dimension; the next aggregator gives you one number per group.
users
| group(users.gender)
| select(users.gender, count(users.id))
4. Cross-model queries
Because relationships are declared in the dataset, you reference columns from related models without writing joins:
users | select(users.name, countries.name)
5. Defining a metric
Name an aggregation so you can reuse it everywhere:
Model users {
measure user_count {
definition: @aql count(users.id) ;;
}
}
Now users | group(users.gender) | select(users.gender, users.user_count) works, and the metric adapts to whatever the surrounding report groups by.
6. Metric context
A metric doesn't carry a fixed number. It evaluates against the surrounding dimensions, filters, relationships, and time window. The "advanced" parts of AQL are mostly about overriding one piece of that context.
7. Level of detail
Make a metric ignore some grouping (of_all), force a fixed grain (exclude), or turn an aggregation into a dimension (dimensionalize). Classic use: percent-of-total.
count(users.id) / (count(users.id) | of_all(countries))
8. Nested aggregation
When the answer needs aggregation-of-aggregation (average monthly new customers, best month for revenue):
users | group(users.created_at | month()) | select(count(users.id)) | average()
9. Time comparisons
Shift a metric back in time and the comparison just becomes arithmetic:
metric revenue_yoy_pct {
definition: @aql
safe_divide(
(revenue - (revenue | relative_period(orders.created_at, interval(-1 year)))) * 100,
revenue | relative_period(orders.created_at, interval(-1 year))
)
;;
}
Where to go next
- Examples & Recipes: copy-paste-ready patterns on a shared e-commerce schema.
- Reference: every function and operator.