window_sum
Definition
A window aggregation function that returns the sum of rows in a range relative to the current row.
Syntax
window_sum(agg_expr)
window_sum(agg_expr, order: order_expr, ...)
window_sum(agg_expr, range, order: order_expr, ...)
window_sum(agg_expr, range, order: order_expr, ..., reset: partition_expr, ...)
window_sum(agg_expr, range, order: order_expr, ..., partition: partition_expr, ...)
window_sum(count(users.id))
window_sum(count(users.id), order: count(users.id) | desc())
window_sum(count(users.id), -2..2, order: users.created_at | month())
window_sum(count(users.id), order: users.created_at | month(), reset: users.gender)
Input
agg_expr
(required): An aggregation expression to be summed.range
(optional): A range of rows to include in the sum. Negative values indicate rows before the current row, and positive values indicate rows after the current row, while 0 indicates the current row. If the beginning or end of the range is not specified, the range will include all rows from the beginning or end of the table. By default, if the range is not specified:- If
order
is specified, the range is..0
(from the first row to the current row). - If
order
is not specified, the range is..
(from the first row to the last row).
- If
order
(required, repeatable): A field that is used for ordering. The order is default to ascending. The order can be set explicitly withasc()
ordesc()
.dangerIf the specified order does not uniquely identify rows, the result of the function can be non-deterministic. For example, if you use
order: users.age
, and there are multiple users with the same age in the same partition, the result can be unexpected.partition
orreset
(repeatable, optional): A field that is used for partitioning the table. If partitions are not specified:- If
order
is specified, the table will be partitioned by all other grouping columns. - If
order
is not specified, the table will be considered as a single partition.
- If
Output
The sum of the current row and the rows within the specified range.
Sample Usages
explore {
dimensions {
users.gender,
orders.status
}
measures {
count(orders.id),
_running_sum: window_sum(count(orders.id), order: orders.status)
}
}
- Result
- SQL
WITH "aql__t1" AS (
SELECT
"users"."gender" AS "users->gender",
"orders"."status" AS "orders->status",
COUNT("orders"."id") AS "count_orders->id"
FROM
"demo"."orders" "orders"
LEFT JOIN "demo"."users" "users" ON "orders"."user_id" = "users"."id"
GROUP BY
1,
2
)
SELECT
"aql__t1"."users->gender" AS "users->gender",
"aql__t1"."orders->status" AS "orders->status",
"aql__t1"."count_orders->id" AS "count_orders->id",
SUM("aql__t1"."count_orders->id") OVER (PARTITION BY "aql__t1"."users->gender" ORDER BY "aql__t1"."orders->status" ASC ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS "_running_sum"
FROM
"aql__t1"
WHERE
"aql__t1"."count_orders->id" IS NOT NULL
Notice that it automatically resets the sum when the gender changes. This is because we only specify order
and thus reset
defaults to gender
. If you want it to not reset, you can order by both gender
and status
.
explore {
dimensions {
users.gender,
orders.status
}
measures {
count(orders.id),
_running_sum: window_sum(count(orders.id), order: users.gender, order: orders.status)
}
}
- Result
- SQL
WITH "aql__t1" AS (
SELECT
"users"."gender" AS "users->gender",
"orders"."status" AS "orders->status",
COUNT("orders"."id") AS "count_orders->id"
FROM
"demo"."orders" "orders"
LEFT JOIN "demo"."users" "users" ON "orders"."user_id" = "users"."id"
GROUP BY
1,
2
)
SELECT
"aql__t1"."users->gender" AS "users->gender",
"aql__t1"."orders->status" AS "orders->status",
"aql__t1"."count_orders->id" AS "count_orders->id",
SUM("aql__t1"."count_orders->id") OVER ( ORDER BY "aql__t1"."users->gender" ASC, "aql__t1"."orders->status" ASC ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS "_running_sum"
FROM
"aql__t1"
WHERE
"aql__t1"."count_orders->id" IS NOT NULL
By default, the range is ..0
(from the first row to the current row). Thus if we want to sum all rows, we can use ..
for the range. And since we are not using relative range, we can omit the order:
parameter.
explore {
dimensions {
users.gender,
orders.status
}
measures {
count(orders.id),
pct: count(orders.id) / window_sum(count(orders.id), ..)
}
}
- Result
- SQL
WITH "aql__t1" AS (
SELECT
"users"."gender" AS "users->gender",
"orders"."status" AS "orders->status",
COUNT("orders"."id") AS "count_orders->id"
FROM
"demo"."orders" "orders"
LEFT JOIN "demo"."users" "users" ON "orders"."user_id" = "users"."id"
GROUP BY
1,
2
)
SELECT
"aql__t1"."users->gender" AS "users->gender",
"aql__t1"."orders->status" AS "orders->status",
"aql__t1"."count_orders->id" AS "count_orders->id",
("aql__t1"."count_orders->id" / (SUM("aql__t1"."count_orders->id") OVER ( ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING))) AS "pct"
FROM
"aql__t1"
WHERE
"aql__t1"."count_orders->id" IS NOT NULL