Table
Rows and columns. The thing AQL passes from one step to the next when you have not aggregated yet.
orders
order_items | filter(...)
products | filter(price > 50)
AQLearn 2.3 / Concept
Source lesson: AQLearn 2.3: Table vs Scalar Outputs. Tangible win: predict whether each step in a pipeline produces a table or a single value, and use that to know which function can come next.
Have you ever tried to write something like "count delivered orders" and gotten a confusing error from AQL?
You hit these pain points:
products | count(products.id) | filter(products.id > 100) and AQL refused. The error message is not always obvious.count versus after a filter. You try things until one works.This lesson solves it: every AQL function has an input shape and an output shape. There are two shapes only: table and scalar. Once you tag each function, every pipeline becomes legal-by-construction.
Rows and columns. The thing AQL passes from one step to the next when you have not aggregated yet.
orders
order_items | filter(...)
products | filter(price > 50)
One value per dimension row. Numbers, text, dates. Whatever you would put in a chart's "value" slot.
count(orders.id)
sum(order_items.quantity)
max(orders.created_at)
| Function | Input shape | Output shape |
|---|---|---|
count, sum, avg, min, max, count_distinct | Table | Scalar |
filter() | Table | Table |
select() | Table | Table |
group() | Table | Table |
where() | Scalar (a metric) | Scalar (filtered metric) |
of_all, keep_grains, dimensionalize, exclude | Scalar | Scalar |
year(), month(), date_trunc() | Scalar (datetime) | Scalar (datetime) |
metric high_id_count = products
| filter(products.id > 100)
| count(products.id);
products is a Table.filter takes a Table and returns a Table.count takes a Table and returns a Scalar.// Type error: count() output is Scalar but filter() expects Table.
metric high_id_count_bad = products
| count(products.id)
| filter(products.id > 100);
products is a Table.count turns it into a Scalar.filter wants a Table, gets a Scalar.where() on the metric instead. where() attaches a filter to a Scalar metric and returns a Scalar.
wheremetric delivered_count = count(orders.id)
| where(orders.status == 'delivered');
This is the same answer as "filter then count" in many cases, expressed at the metric level. See AQLearn: where vs filter vs explore filters for the deep dive.
Walk left to right. Tag the shape after each step.
order_items // Table
| filter(order_items.quantity > 1) // Table
| sum(order_items.quantity) // Scalar
users // Table
| filter(users.gender == 'Female') // Table
| count(users.id) // Scalar
| where(countries.name == 'Vietnam') // Scalar
products | filter(products.id > 100) | count(products.id). Run and read the result.products | count(products.id) | filter(...). Read the error AQL gives you.count(products.id) | where(products.id > 100) and confirm the value matches the first try.Next: Function: select & group (1). The two Table-in, Table-out building blocks that power custom aggregations.