跳至主要内容

聚合函数组合器

聚合函数的名称可以附加后缀。这会改变聚合函数的工作方式。

-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 类型。

示例

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 对于相同的数据不是不变的,因为中间状态中数据的顺序可能会发生变化,尽管这不会影响这些数据的摄取。

要使用这些状态,请使用

-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)

参数

  • startresampling_key 值的整个所需区间的起始值。
  • stopresampling_key 值的整个所需区间的结束值。整个区间不包括 stop[start, stop)
  • step — 将整个区间分成子区间的步长。aggFunction 将独立地在每个子区间上执行。
  • resampling_key — 用于将数据分成区间的列的值。
  • aggFunction_paramsaggFunction 参数。

返回值

  • 每个子区间的 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,但仅处理指定额外表达式具有最大值的那些行。