Skip to main content

What AQL is for

Before we touch pipes, filters, or grouping, it's worth seeing the destination. AQL exists to do one thing well: define metrics once, then query them anywhere.

A metric in 10 lines​

A metric is a named, reusable aggregation. Here's one:

metric total_revenue {
label: 'Total Revenue'
type: 'number'
definition: @aql sum(order_items.quantity * products.price) ;;
}

That's it. No GROUP BY, no JOIN, no per-report scaffolding. Just the calculation. The metric travels with its definition.

Same metric, three reports​

Drop total_revenue into three different reports and it adapts to each:

// Report 1: no grouping → grand total
explore { measures { total_revenue } }
// → $4,283,512

// Report 2: grouped by country → revenue per country
explore { dimensions { countries.name } measures { total_revenue } }
// → US: $2.1M, UK: $890K, ...

// Report 3: grouped by month, filtered to 2024 → monthly trend
explore {
dimensions { orders.created_at | month() }
measures { total_revenue }
filters { orders.created_at matches @2024 }
}
// → Jan 2024: $312K, Feb 2024: $358K, ...

Same definition. Three different numbers, three different shapes. That's the part SQL can't do cleanly. In SQL you'd write three separate queries with copy-pasted aggregation logic, and any change to "what revenue means" would mean editing all three.

What the rest of Foundations teaches​

To write metrics like total_revenue, you need to know the primitives that go inside the definition:

Once those click, the Metrics group covers how metrics interact with related models, how to name and reuse them, and how the surrounding report context shapes what they return.

Next​

→ The pipe operator: the single biggest reason AQL reads differently from SQL.


Open Markdown
Let us know what you think about this document :)