聚合函数组合器
聚合函数的名称可以附加后缀。这会改变聚合函数的工作方式。
-If
后缀 -If 可以附加到任何聚合函数的名称上。在这种情况下,聚合函数接受一个额外的参数 - 一个条件(Uint8 类型)。聚合函数仅处理触发条件的行。如果条件甚至一次都没有被触发,它将返回一个默认值(通常为零或空字符串)。
示例:sumIf(column, cond)
,countIf(cond)
,avgIf(x, cond)
,quantilesTimingIf(level1, level2)(x, cond)
,argMinIf(arg, val, cond)
等等。
使用条件聚合函数,您可以一次计算多个条件的聚合,而无需使用子查询和 JOIN
。例如,条件聚合函数可以用于实现分段比较功能。
-Array
-Array 后缀可以附加到任何聚合函数。在这种情况下,聚合函数接受 ‘Array(T)’ 类型(数组)的参数,而不是 ‘T’ 类型的参数。如果聚合函数接受多个参数,则这些参数必须是长度相等的数组。在处理数组时,聚合函数的工作方式类似于原始聚合函数跨所有数组元素。
示例 1:sumArray(arr)
- 汇总所有 ‘arr’ 数组的所有元素。在本例中,可以更简单地写成:sum(arraySum(arr))
。
示例 2:uniqArray(arr)
– 计算所有 ‘arr’ 数组中唯一元素的数量。这可以用更简单的方式完成:uniq(arrayJoin(arr))
,但并非总是可以在查询中添加 ‘arrayJoin’。
-If 和 -Array 可以组合使用。但是,‘Array’ 必须在 ‘If’ 之前。示例:uniqArrayIf(arr, cond)
,quantilesTimingArrayIf(level1, level2)(arr, cond)
。由于此顺序,‘cond’ 参数不会是数组。
-Map
-Map 后缀可以附加到任何聚合函数。这将创建一个聚合函数,该函数将 Map 类型作为参数,并使用指定的聚合函数分别聚合 map 的每个键的值。结果也是 Map 类型。
示例
CREATE TABLE map_map(
date Date,
timeslot DateTime,
status Map(String, UInt64)
) ENGINE = Log;
INSERT INTO map_map VALUES
('2000-01-01', '2000-01-01 00:00:00', (['a', 'b', 'c'], [10, 10, 10])),
('2000-01-01', '2000-01-01 00:00:00', (['c', 'd', 'e'], [10, 10, 10])),
('2000-01-01', '2000-01-01 00:01:00', (['d', 'e', 'f'], [10, 10, 10])),
('2000-01-01', '2000-01-01 00:01:00', (['f', 'g', 'g'], [10, 10, 10]));
SELECT
timeslot,
sumMap(status),
avgMap(status),
minMap(status)
FROM map_map
GROUP BY timeslot;
┌────────────timeslot─┬─sumMap(status)───────────────────────┬─avgMap(status)───────────────────────┬─minMap(status)───────────────────────┐
│ 2000-01-01 00:00:00 │ {'a':10,'b':10,'c':20,'d':10,'e':10} │ {'a':10,'b':10,'c':10,'d':10,'e':10} │ {'a':10,'b':10,'c':10,'d':10,'e':10} │
│ 2000-01-01 00:01:00 │ {'d':10,'e':10,'f':20,'g':20} │ {'d':10,'e':10,'f':10,'g':10} │ {'d':10,'e':10,'f':10,'g':10} │
└─────────────────────┴──────────────────────────────────────┴──────────────────────────────────────┴──────────────────────────────────────┘
-SimpleState
如果应用此组合器,则聚合函数返回相同的值,但类型不同。这是一个 SimpleAggregateFunction(...),可以存储在表中以与 AggregatingMergeTree 表一起使用。
语法
<aggFunction>SimpleState(x)
参数
x
— 聚合函数参数。
返回值
具有 SimpleAggregateFunction(...)
类型的聚合函数的值。
示例
查询
WITH anySimpleState(number) AS c SELECT toTypeName(c), c FROM numbers(1);
结果
┌─toTypeName(c)────────────────────────┬─c─┐
│ SimpleAggregateFunction(any, UInt64) │ 0 │
└──────────────────────────────────────┴───┘
-State
如果应用此组合器,则聚合函数不会返回结果值(例如,uniq 函数的唯一值数量),而是聚合的中间状态(对于 uniq
,这是用于计算唯一值数量的哈希表)。这是一个 AggregateFunction(...)
,可用于进一步处理或存储在表中以便稍后完成聚合。
请注意,-MapState 对于相同的数据不是不变的,因为中间状态的数据顺序可能会更改,但这不会影响此数据的摄取。
要使用这些状态,请使用
- AggregatingMergeTree 表引擎。
- finalizeAggregation 函数。
- runningAccumulate 函数。
- -Merge 组合器。
- -MergeState 组合器。
-Merge
如果应用此组合器,则聚合函数将中间聚合状态作为参数,组合这些状态以完成聚合,并返回结果值。
-MergeState
以与 -Merge 组合器相同的方式合并中间聚合状态。但是,它不返回结果值,而是返回中间聚合状态,类似于 -State 组合器。
-ForEach
将用于表的聚合函数转换为用于数组的聚合函数,该函数聚合相应的数组项并返回结果数组。例如,对于数组 [1, 2]
,[3, 4, 5]
和 [6, 7]
,sumForEach
在将相应的数组项加在一起后返回结果 [10, 13, 5]
。
-Distinct
每个唯一的参数组合将仅聚合一次。重复值将被忽略。示例:sum(DISTINCT x)
(或 sumDistinct(x)
),groupArray(DISTINCT x)
(或 groupArrayDistinct(x)
),corrStable(DISTINCT x, y)
(或 corrStableDistinct(x, y)
)等等。
-OrDefault
更改聚合函数的行为。
如果聚合函数没有输入值,则使用此组合器,它将返回其返回数据类型的默认值。适用于可以接受空输入数据的聚合函数。
-OrDefault
可以与其他组合器一起使用。
语法
<aggFunction>OrDefault(x)
参数
x
— 聚合函数参数。
返回值
如果没有要聚合的内容,则返回聚合函数返回类型的默认值。
类型取决于使用的聚合函数。
示例
查询
SELECT avg(number), avgOrDefault(number) FROM numbers(0)
结果
┌─avg(number)─┬─avgOrDefault(number)─┐
│ nan │ 0 │
└─────────────┴──────────────────────┘
此外,-OrDefault
可以与另一个组合器一起使用。当聚合函数不接受空输入时,这很有用。
查询
SELECT avgOrDefaultIf(x, x > 10)
FROM
(
SELECT toDecimal32(1.23, 2) AS x
)
结果
┌─avgOrDefaultIf(x, greater(x, 10))─┐
│ 0.00 │
└───────────────────────────────────┘
-OrNull
更改聚合函数的行为。
此组合器将聚合函数的结果转换为 Nullable 数据类型。如果聚合函数没有要计算的值,则返回 NULL。
-OrNull
可以与其他组合器一起使用。
语法
<aggFunction>OrNull(x)
参数
x
— 聚合函数参数。
返回值
- 聚合函数的结果,转换为
Nullable
数据类型。 NULL
,如果没有要聚合的内容。
类型:Nullable(聚合函数返回类型)
。
示例
在聚合函数的末尾添加 -orNull
。
查询
SELECT sumOrNull(number), toTypeName(sumOrNull(number)) FROM numbers(10) WHERE number > 10
结果
┌─sumOrNull(number)─┬─toTypeName(sumOrNull(number))─┐
│ ᴺᵁᴸᴸ │ Nullable(UInt64) │
└───────────────────┴───────────────────────────────┘
此外,-OrNull
可以与另一个组合器一起使用。当聚合函数不接受空输入时,这很有用。
查询
SELECT avgOrNullIf(x, x > 10)
FROM
(
SELECT toDecimal32(1.23, 2) AS x
)
结果
┌─avgOrNullIf(x, greater(x, 10))─┐
│ ᴺᵁᴸᴸ │
└────────────────────────────────┘
-Resample
允许您将数据划分为组,然后分别聚合这些组中的数据。组是通过将一个列中的值拆分为间隔来创建的。
<aggFunction>Resample(start, end, step)(<aggFunction_params>, resampling_key)
参数
start
—resampling_key
值的整个所需间隔的起始值。stop
—resampling_key
值的整个所需间隔的结束值。整个间隔不包括stop
值[start, stop)
。step
— 将整个间隔分隔为子间隔的步长。aggFunction
在每个子间隔上独立执行。resampling_key
— 用于将数据分隔为间隔的列的值。aggFunction_params
—aggFunction
参数。
返回值
- 每个子间隔的
aggFunction
结果数组。
示例
考虑具有以下数据的 people
表
┌─name───┬─age─┬─wage─┐
│ John │ 16 │ 10 │
│ Alice │ 30 │ 15 │
│ Mary │ 35 │ 8 │
│ Evelyn │ 48 │ 11.5 │
│ David │ 62 │ 9.9 │
│ Brian │ 60 │ 16 │
└────────┴─────┴──────┘
让我们获取年龄在 [30,60)
和 [60,75)
区间内的人员姓名。由于我们使用整数表示年龄,因此我们得到的年龄在 [30, 59]
和 [60, 74]
区间内。
为了在数组中聚合名称,我们使用 groupArray 聚合函数。它接受一个参数。在我们的例子中,它是 name
列。groupArrayResample
函数应使用 age
列按年龄聚合名称。为了定义所需的间隔,我们将 30, 75, 30
参数传递到 groupArrayResample
函数中。
SELECT groupArrayResample(30, 75, 30)(name, age) FROM people
┌─groupArrayResample(30, 75, 30)(name, age)─────┐
│ [['Alice','Mary','Evelyn'],['David','Brian']] │
└───────────────────────────────────────────────┘
考虑结果。
John
不在样本中,因为他太年轻了。其他人根据指定的年龄间隔分布。
现在让我们计算指定年龄间隔内的人员总数及其平均工资。
SELECT
countResample(30, 75, 30)(name, age) AS amount,
avgResample(30, 75, 30)(wage, age) AS avg_wage
FROM people
┌─amount─┬─avg_wage──────────────────┐
│ [3,2] │ [11.5,12.949999809265137] │
└────────┴───────────────────────────┘
-ArgMin
-ArgMin 后缀可以附加到任何聚合函数的名称上。在这种情况下,聚合函数接受一个额外的参数,该参数应该是任何可比较的表达式。聚合函数仅处理指定额外表达式具有最小值的行。
示例:sumArgMin(column, expr)
,countArgMin(expr)
,avgArgMin(x, expr)
等等。
-ArgMax
类似于后缀 -ArgMin,但仅处理指定额外表达式具有最大值的行。