> ## Documentation Index
> Fetch the complete documentation index at: https://private-7c7dfe99-mintlify-8c05c8a2.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

> 参数化聚合函数的文档

# 参数化聚合函数

某些聚合函数不仅可以接受作为实参的列 (用于压缩) ，还可以接受一组参数——即用于初始化的常量。其语法使用两对括号，而不是一对：第一对用于参数，第二对用于实参。

<div id="histogram">
  ## histogram
</div>

计算自适应直方图。结果不保证精确。

```sql theme={null}
histogram(number_of_bins)(values)
```

该函数使用 [A Streaming Parallel Decision Tree Algorithm](http://jmlr.org/papers/volume11/ben-haim10a/ben-haim10a.pdf)。随着新数据进入函数，直方图各个 bin 的边界会动态调整。通常情况下，各 bin 的宽度并不相等。

**参数**

`values` — 生成输入值的 [表达式](/zh/reference/syntax#expressions)。

**参数设置**

`number_of_bins` — 直方图中 bin 数量的上限。函数会自动计算 bin 的数量。它会尽量达到指定的 bin 数量；如果无法达到，则会使用更少的 bin。

**返回值**

* 由 [Tuple](/zh/reference/data-types/tuple) 组成的 [Array](/zh/reference/data-types/array)，格式如下：

  ```
  [(lower_1, upper_1, height_1), ... (lower_N, upper_N, height_N)]
  ```

  * `lower` — bin 的下界。
  * `upper` — bin 的上界。
  * `height` — 计算得到的 bin 高度。

**示例**

```sql theme={null}
SELECT histogram(5)(number + 1)
FROM (
    SELECT *
    FROM system.numbers
    LIMIT 20
)
```

```text theme={null}
┌─histogram(5)(plus(number, 1))───────────────────────────────────────────┐
│ [(1,4.5,4),(4.5,8.5,4),(8.5,12.75,4.125),(12.75,17,4.625),(17,20,3.25)] │
└─────────────────────────────────────────────────────────────────────────┘
```

你可以使用 [bar](/zh/reference/functions/regular-functions/other-functions#bar) 函数将数据可视化为直方图，例如：

```sql theme={null}
WITH histogram(5)(rand() % 100) AS hist
SELECT
    arrayJoin(hist).3 AS height,
    bar(height, 0, 6, 5) AS bar
FROM
(
    SELECT *
    FROM system.numbers
    LIMIT 20
)
```

```text theme={null}
┌─height─┬─bar───┐
│  2.125 │ █▋    │
│   3.25 │ ██▌   │
│  5.625 │ ████▏ │
│  5.625 │ ████▏ │
│  3.375 │ ██▌   │
└────────┴───────┘
```

在这种情况下，需要注意的是，你并不知道直方图各个分箱的边界。

<div id="sequencematch">
  ## sequenceMatch
</div>

检查序列中是否包含与模式匹配的事件链。

**语法**

```sql theme={null}
sequenceMatch(pattern)(timestamp, cond1, cond2, ...)
```

<Note>
  在同一秒发生的事件在序列中的先后顺序可能不确定，这会影响结果。
</Note>

**参数**

* `timestamp` — 视为包含时间数据的列。典型数据类型为 `Date` 和 `DateTime`。你也可以使用任何受支持的 [UInt](/zh/reference/data-types/int-uint) 数据类型。

* `cond1`, `cond2` — 描述事件链的条件。数据类型：`UInt8`。最多可传入 32 个条件参数。函数只会考虑这些条件所描述的事件。如果序列中包含未在任何条件中描述的数据，函数会跳过它们。

**参数**

* `pattern` — 模式字符串。请参见[模式语法](#pattern-syntax)。

**返回值**

* 1，表示模式匹配。
* 0，表示模式不匹配。

类型：`UInt8`。

<div id="pattern-syntax">
  #### 模式语法
</div>

* `(?N)` — 匹配位置 `N` 处的条件参数。条件的编号范围为 `[1, 32]`。例如，`(?1)` 匹配传递给 `cond1` 参数的值。

* `.*` — 匹配任意数量的事件。匹配模式中的这一元素时，无需提供条件参数。

* `(?t operator value)` — 设置两个事件之间应间隔的时间 (以秒为单位) 。例如，模式 `(?1)(?t>1800)(?2)` 匹配彼此相隔超过 1800 秒的事件。这两个事件之间可以穿插任意数量的其他事件。你可以使用 `>=`、`>`、`<`、`<=`、`==` 运算符。

**示例**

假设 `t` 表中有如下数据：

```text theme={null}
┌─time─┬─number─┐
│    1 │      1 │
│    2 │      3 │
│    3 │      2 │
└──────┴────────┘
```

执行此查询：

```sql theme={null}
SELECT sequenceMatch('(?1)(?2)')(time, number = 1, number = 2) FROM t
```

```text theme={null}
┌─sequenceMatch('(?1)(?2)')(time, equals(number, 1), equals(number, 2))─┐
│                                                                     1 │
└───────────────────────────────────────────────────────────────────────┘
```

该函数找到了编号 2 紧跟在编号 1 之后的事件链。它跳过了两者之间的编号 3，因为这个编号没有被定义为事件。如果我们希望在搜索示例中给出的事件链时将这个编号也考虑进去，就应该为它添加一个条件。

```sql theme={null}
SELECT sequenceMatch('(?1)(?2)')(time, number = 1, number = 2, number = 3) FROM t
```

```text theme={null}
┌─sequenceMatch('(?1)(?2)')(time, equals(number, 1), equals(number, 2), equals(number, 3))─┐
│                                                                                        0 │
└──────────────────────────────────────────────────────────────────────────────────────────┘
```

在这种情况下，由于编号 3 的事件发生在 1 和 2 之间，因此该函数无法找到与该模式匹配的事件链。如果在同样的情况下检查编号 4 的条件，这个序列就会匹配该模式。

```sql theme={null}
SELECT sequenceMatch('(?1)(?2)')(time, number = 1, number = 2, number = 4) FROM t
```

```text theme={null}
┌─sequenceMatch('(?1)(?2)')(time, equals(number, 1), equals(number, 2), equals(number, 4))─┐
│                                                                                        1 │
└──────────────────────────────────────────────────────────────────────────────────────────┘
```

**另请参见**

* [sequenceCount](#sequencecount)

<div id="sequencecount">
  ## sequenceCount
</div>

统计与模式匹配的事件链数量。该函数会查找彼此不重叠的事件链。当前事件链匹配完成后，才会开始查找下一条事件链。

<Note>
  在同一秒内发生的事件在序列中的顺序可能是未定义的，这会影响结果。
</Note>

**语法**

```sql theme={null}
sequenceCount(pattern)(timestamp, cond1, cond2, ...)
```

**参数**

* `timestamp` — 视为包含时间数据的列。典型的数据类型有 `Date` 和 `DateTime`。你也可以使用任何受支持的 [UInt](/zh/reference/data-types/int-uint) 数据类型。

* `cond1`, `cond2` — 用于描述事件链的条件。数据类型：`UInt8`。最多可以传入 32 个条件参数。函数只会考虑这些条件中描述的事件。如果序列中包含未被任何条件描述的数据，函数会跳过这些数据。

**参数**

* `pattern` — 模式字符串。请参见 [模式语法](#pattern-syntax)。

**返回值**

* 匹配到的非重叠事件链数量。

类型：`UInt64`。

**示例**

假设 `t` 表中的数据如下：

```text theme={null}
┌─time─┬─number─┐
│    1 │      1 │
│    2 │      3 │
│    3 │      2 │
│    4 │      1 │
│    5 │      3 │
│    6 │      2 │
└──────┴────────┘
```

统计数字 1 之后出现数字 2 的次数，两者之间可以有任意数量的其他数字：

```sql theme={null}
SELECT sequenceCount('(?1).*(?2)')(time, number = 1, number = 2) FROM t
```

```text theme={null}
┌─sequenceCount('(?1).*(?2)')(time, equals(number, 1), equals(number, 2))─┐
│                                                                       2 │
└─────────────────────────────────────────────────────────────────────────┘
```

<div id="sequencematchevents">
  ## sequenceMatchEvents
</div>

返回与模式匹配的最长事件链中各事件的时间戳。

<Note>
  在同一秒内发生的事件，在序列中的先后顺序可能不确定，从而影响结果。
</Note>

**语法**

```sql theme={null}
sequenceMatchEvents(pattern)(timestamp, cond1, cond2, ...)
```

**参数**

* `timestamp` — 视为包含时间数据的列。典型的数据类型包括 `Date` 和 `DateTime`。您也可以使用任意受支持的 [UInt](/zh/reference/data-types/int-uint) 数据类型。

* `cond1`, `cond2` — 用于描述事件链的条件。数据类型：`UInt8`。最多可传入 32 个条件参数。函数只会考虑这些条件中描述的事件。如果序列中包含未在任何条件中描述的数据，函数会跳过这些数据。

**参数**

* `pattern` — 模式字符串。请参见 [模式语法](#pattern-syntax)。

**返回值**

* 事件链中与条件参数 (?N) 匹配的时间戳数组。数组中的位置与 模式 中条件参数的位置对应。

类型：Array。

**示例**

假设 `t` 表中的数据如下：

```text theme={null}
┌─time─┬─number─┐
│    1 │      1 │
│    2 │      3 │
│    3 │      2 │
│    4 │      1 │
│    5 │      3 │
│    6 │      2 │
└──────┴────────┘
```

返回最长事件链中各事件的时间戳

```sql theme={null}
SELECT sequenceMatchEvents('(?1).*(?2).*(?1)(?3)')(time, number = 1, number = 2, number = 4) FROM t
```

```text theme={null}
┌─sequenceMatchEvents('(?1).*(?2).*(?1)(?3)')(time, equals(number, 1), equals(number, 2), equals(number, 4))─┐
│ [1,3,4]                                                                                                    │
└────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
```

**另请参阅**

* [sequenceMatch](#sequencematch)

<div id="windowfunnel">
  ## windowFunnel
</div>

在滑动时间窗口中搜索事件链，并计算该事件链内已发生事件的最大数量。

该函数按以下算法工作：

* 函数会搜索满足事件链中第一个条件的数据，并将事件计数器设为 1。此时滑动窗口开始计时。

* 如果事件链中的事件在窗口内按顺序发生，则计数器会递增；如果事件顺序被打断，则计数器不会递增。

* 如果数据中存在多个完成程度不同的事件链，函数只会输出最长事件链的长度。

**语法**

```sql theme={null}
windowFunnel(window, [mode, [mode, ... ]])(timestamp, cond1, cond2, ..., condN)
```

**Arguments**

* `timestamp` — 包含时间戳的列名。支持的数据类型：[Date](/zh/reference/data-types/date)、[DateTime](/zh/reference/data-types/datetime) 以及其他无符号整数类型 (注意，虽然 `timestamp` 支持 `UInt64` 类型，但其值不能超过 Int64 的最大值，即 2^63 - 1) 。
* `cond` — 描述事件链的条件或数据。[UInt8](/zh/reference/data-types/int-uint)。

**Parameters**

* `window` — 滑动窗口的长度，即第一个条件与最后一个条件之间的时间间隔。`window` 的单位取决于 `timestamp` 本身，可能有所不同。其判定依据为表达式 `timestamp of cond1 <= timestamp of cond2 <= ... <= timestamp of condN <= timestamp of cond1 + window`。
* `mode` — 可选参数。可以设置一个或多个模式。
  * `'strict_deduplication'` — 如果同一条件在事件序列中重复成立，则该重复事件会中断后续处理。注意：如果同一事件同时满足多个条件，结果可能不符合预期。
  * `'strict_order'` — 不允许插入其他事件。例如，在 `A->B->D->C` 这种情况下，会在 `D` 处停止查找 `A->B->C`，最大事件级别为 2。
  * `'strict_increase'` — 仅对时间戳严格递增的事件应用条件。
  * `'strict_once'` — 在事件链中，每个事件只计数一次，即使它多次满足条件也是如此。
  * `'allow_reentry'` — 忽略违反严格顺序的事件。例如，在 A->A->B->C 这种情况下，会通过忽略多余的 A 找到 A->B->C，最大事件级别为 3。

**Returned value**

滑动时间窗口内，事件链中连续触发条件的最大数量。
将分析查询结果中的所有事件链。

类型：`Integer`。

**Example**

判断给定时间段是否足以让用户在网店中挑选一部手机并购买两次。

设置以下事件链：

1. 用户登录其网店账户 (`eventID = 1003`) 。
2. 用户搜索手机 (`eventID = 1007, product = 'phone'`) 。
3. 用户下单 (`eventID = 1009`) 。
4. 用户再次下单 (`eventID = 1010`) 。

输入表：

```text theme={null}
┌─event_date─┬─user_id─┬───────────timestamp─┬─eventID─┬─product─┐
│ 2019-01-28 │       1 │ 2019-01-29 10:00:00 │    1003 │ phone   │
└────────────┴─────────┴─────────────────────┴─────────┴─────────┘
┌─event_date─┬─user_id─┬───────────timestamp─┬─eventID─┬─product─┐
│ 2019-01-31 │       1 │ 2019-01-31 09:00:00 │    1007 │ phone   │
└────────────┴─────────┴─────────────────────┴─────────┴─────────┘
┌─event_date─┬─user_id─┬───────────timestamp─┬─eventID─┬─product─┐
│ 2019-01-30 │       1 │ 2019-01-30 08:00:00 │    1009 │ phone   │
└────────────┴─────────┴─────────────────────┴─────────┴─────────┘
┌─event_date─┬─user_id─┬───────────timestamp─┬─eventID─┬─product─┐
│ 2019-02-01 │       1 │ 2019-02-01 08:00:00 │    1010 │ phone   │
└────────────┴─────────┴─────────────────────┴─────────┴─────────┘
```

查看用户 `user_id` 在 2019 年 1 月至 2 月期间，在该事件链中最多能进行到哪一步。

```sql title="Query" theme={null}
SELECT
    level,
    count() AS c
FROM
(
    SELECT
        user_id,
        windowFunnel(6048000000000000)(timestamp, eventID = 1003, eventID = 1009, eventID = 1007, eventID = 1010) AS level
    FROM trend
    WHERE (event_date >= '2019-01-01') AND (event_date <= '2019-02-02')
    GROUP BY user_id
)
GROUP BY level
ORDER BY level ASC;
```

```text title="Response" theme={null}
┌─level─┬─c─┐
│     4 │ 1 │
└───────┴───┘
```

**allow\_reentry 模式示例**

本示例说明了 `allow_reentry` 模式如何与用户重入模式一起使用：

```sql theme={null}
-- 样本数据：用户访问结账 -> 商品详情 -> 再次结账 -> 支付
-- 不使用 allow_reentry：停在第 2 级（商品详情页）
-- 使用 allow_reentry：到达第 4 级（完成支付）

SELECT
    level,
    count() AS users
FROM
(
    SELECT
        user_id,
        windowFunnel(3600, 'strict_order', 'allow_reentry')(
            timestamp,
            action = 'begin_checkout',      -- 第 1 步：开始结账
            action = 'view_product_detail', -- 第 2 步：查看商品详情
            action = 'begin_checkout',      -- 第 3 步：再次开始结账（重入）
            action = 'complete_payment'     -- 第 4 步：完成支付
        ) AS level
    FROM user_events
    WHERE event_date = today()
    GROUP BY user_id
)
GROUP BY level
ORDER BY level ASC;
```

<div id="retention">
  ## retention
</div>

该函数接受一组条件作为参数，参数数量为 1 到 32 个，类型均为 `UInt8`，用于指示某个事件是否满足某一条件。
任何条件都可以作为参数指定 (如 [WHERE](/zh/reference/statements/select/where) 中所示) 。

除第一个条件外，其余条件均与第一个条件成对应用：如果第一个和第二个条件都为真，则第二个结果为真；如果第一个和第三个条件都为真，则第三个结果为真；以此类推。

**语法**

```sql theme={null}
retention(cond1, cond2, ..., cond32);
```

**参数**

* `cond` — 返回 `UInt8` 结果 (1 或 0) 的表达式。

**返回值**

由 1 或 0 组成的数组。

* 1 — 事件满足条件。
* 0 — 事件不满足条件。

类型：`UInt8`。

**示例**

下面以一个计算 `retention` 函数来确定网站流量的示例进行说明。

**1.** 创建一个表作为示例。

```sql title="Query" theme={null}
CREATE TABLE retention_test(date Date, uid Int32) ENGINE = Memory;

INSERT INTO retention_test SELECT '2020-01-01', number FROM numbers(5);
INSERT INTO retention_test SELECT '2020-01-02', number FROM numbers(10);
INSERT INTO retention_test SELECT '2020-01-03', number FROM numbers(15);
```

输入表：

```sql title="Query" theme={null}
SELECT * FROM retention_test
```

```text title="Response" theme={null}
┌───────date─┬─uid─┐
│ 2020-01-01 │   0 │
│ 2020-01-01 │   1 │
│ 2020-01-01 │   2 │
│ 2020-01-01 │   3 │
│ 2020-01-01 │   4 │
└────────────┴─────┘
┌───────date─┬─uid─┐
│ 2020-01-02 │   0 │
│ 2020-01-02 │   1 │
│ 2020-01-02 │   2 │
│ 2020-01-02 │   3 │
│ 2020-01-02 │   4 │
│ 2020-01-02 │   5 │
│ 2020-01-02 │   6 │
│ 2020-01-02 │   7 │
│ 2020-01-02 │   8 │
│ 2020-01-02 │   9 │
└────────────┴─────┘
┌───────date─┬─uid─┐
│ 2020-01-03 │   0 │
│ 2020-01-03 │   1 │
│ 2020-01-03 │   2 │
│ 2020-01-03 │   3 │
│ 2020-01-03 │   4 │
│ 2020-01-03 │   5 │
│ 2020-01-03 │   6 │
│ 2020-01-03 │   7 │
│ 2020-01-03 │   8 │
│ 2020-01-03 │   9 │
│ 2020-01-03 │  10 │
│ 2020-01-03 │  11 │
│ 2020-01-03 │  12 │
│ 2020-01-03 │  13 │
│ 2020-01-03 │  14 │
└────────────┴─────┘
```

**2.** 使用 `retention` 函数按唯一 ID `uid` 对用户分组。

```sql title="Query" theme={null}
SELECT
    uid,
    retention(date = '2020-01-01', date = '2020-01-02', date = '2020-01-03') AS r
FROM retention_test
WHERE date IN ('2020-01-01', '2020-01-02', '2020-01-03')
GROUP BY uid
ORDER BY uid ASC
```

```text title="Response" theme={null}
┌─uid─┬─r───────┐
│   0 │ [1,1,1] │
│   1 │ [1,1,1] │
│   2 │ [1,1,1] │
│   3 │ [1,1,1] │
│   4 │ [1,1,1] │
│   5 │ [0,0,0] │
│   6 │ [0,0,0] │
│   7 │ [0,0,0] │
│   8 │ [0,0,0] │
│   9 │ [0,0,0] │
│  10 │ [0,0,0] │
│  11 │ [0,0,0] │
│  12 │ [0,0,0] │
│  13 │ [0,0,0] │
│  14 │ [0,0,0] │
└─────┴─────────┘
```

**3.** 计算每天的网站访问总次数。

```sql title="Query" theme={null}
SELECT
    sum(r[1]) AS r1,
    sum(r[2]) AS r2,
    sum(r[3]) AS r3
FROM
(
    SELECT
        uid,
        retention(date = '2020-01-01', date = '2020-01-02', date = '2020-01-03') AS r
    FROM retention_test
    WHERE date IN ('2020-01-01', '2020-01-02', '2020-01-03')
    GROUP BY uid
)
```

```text title="Response" theme={null}
┌─r1─┬─r2─┬─r3─┐
│  5 │  5 │  5 │
└────┴────┴────┘
```

其中：

* `r1`- 在 2020-01-01 访问网站的独立访客数量 (`cond1` 条件) 。
* `r2`- 在 2020-01-01 至 2020-01-02 之间某个特定时间段内访问网站的独立访客数量 (`cond1` 和 `cond2` 条件) 。
* `r3`- 在 2020-01-01 和 2020-01-03 的某个特定时间段内访问网站的独立访客数量 (`cond1` 和 `cond3` 条件) 。

<div id="uniquptonx">
  ## uniqUpTo(N)(x)
</div>

计算参数中不同值的数量，最多到指定上限 `N`。如果参数的不同值个数大于 `N`，此函数返回 `N` + 1；否则返回精确值。

建议在 `N` 较小时使用，最多到 10。`N` 的最大值为 100。

对于聚合函数的状态，此函数占用的内存量等于 1 + `N` \* 单个值的字节大小。
处理字符串时，此函数会存储一个 8 字节的非加密哈希；对于字符串，计算结果为近似值。

例如，假设你有一个表，用于记录网站用户发出的每一次搜索查询。表中的每一行表示一次搜索查询，列包括用户 ID、搜索查询以及该查询的时间戳。你可以使用 `uniqUpTo` 生成一份报告，只显示至少有 5 个不同用户搜索过的关键词。

```sql theme={null}
SELECT SearchPhrase
FROM SearchLog
GROUP BY SearchPhrase
HAVING uniqUpTo(4)(UserID) >= 5
```

`uniqUpTo(4)(UserID)` 会为每个 `SearchPhrase` 计算唯一 `UserID` 值的数量，但最多只统计 4 个不同值。如果某个 `SearchPhrase` 的唯一 `UserID` 值超过 4 个，该函数会返回 5 (4 + 1) 。随后，`HAVING` 子句会过滤掉唯一 `UserID` 值数量少于 5 的 `SearchPhrase` 值。这样，你就会得到一个至少被 5 个不同用户使用过的搜索关键词列表。

<div id="summapfiltered">
  ## sumMapFiltered
</div>

此函数的行为与 [sumMap](/zh/reference/functions/aggregate-functions/sumMap) 相同，不同之处在于它还接受一个作为参数的键数组，并据此进行过滤。这在处理高基数键时尤其有用。

**语法**

`sumMapFiltered(keys_to_keep)(keys, values)`

**参数**

* `keys_to_keep`：用于过滤的 [Array](/zh/reference/data-types/array) 键数组。
* `keys`：键的 [Array](/zh/reference/data-types/array)。
* `values`：值的 [Array](/zh/reference/data-types/array)。

**返回值**

* 返回一个由两个数组组成的元组：按排序顺序排列的键，以及对应键汇总后的值。

**示例**

```sql title="Query" theme={null}
CREATE TABLE sum_map
(
    `date` Date,
    `timeslot` DateTime,
    `statusMap` Nested(status UInt16, requests UInt64)
)
ENGINE = Log

INSERT INTO sum_map VALUES
    ('2000-01-01', '2000-01-01 00:00:00', [1, 2, 3], [10, 10, 10]),
    ('2000-01-01', '2000-01-01 00:00:00', [3, 4, 5], [10, 10, 10]),
    ('2000-01-01', '2000-01-01 00:01:00', [4, 5, 6], [10, 10, 10]),
    ('2000-01-01', '2000-01-01 00:01:00', [6, 7, 8], [10, 10, 10]);
```

```sql title="Query" theme={null}
SELECT sumMapFiltered([1, 4, 8])(statusMap.status, statusMap.requests) FROM sum_map;
```

```response title="Response" theme={null}
   ┌─sumMapFiltered([1, 4, 8])(statusMap.status, statusMap.requests)─┐
1. │ ([1,4,8],[10,20,10])                                            │
   └─────────────────────────────────────────────────────────────────┘
```

<div id="summapfilteredwithoverflow">
  ## sumMapFilteredWithOverflow
</div>

此函数的行为与 [sumMap](/zh/reference/functions/aggregate-functions/sumMap) 相同，但它还额外接受一个用于过滤的键数组参数。在处理高基数键时，这一点尤其有用。它与 [sumMapFiltered](#summapfiltered) 函数的不同之处在于，它按溢出语义进行求和——也就是说，求和结果返回的数据类型与参数的数据类型相同。

**语法**

`sumMapFilteredWithOverflow(keys_to_keep)(keys, values)`

**参数**

* `keys_to_keep`：[Array](/zh/reference/data-types/array) 类型的键数组，用于过滤。
* `keys`：[Array](/zh/reference/data-types/array) 类型的键数组。
* `values`：[Array](/zh/reference/data-types/array) 类型的值数组。

**返回值**

* 返回一个包含两个数组的元组：按顺序排序的键，以及对应键求和后的值。

**示例**

在此示例中，我们创建一个 `sum_map` 表，向其中 insert 一些数据，然后使用 `sumMapFilteredWithOverflow`、`sumMapFiltered` 和 `toTypeName` 函数来比较结果。在创建的表中，`requests` 的类型为 `UInt8`，`sumMapFiltered` 会将求和值的类型提升为 `UInt64` 以避免溢出，而 `sumMapFilteredWithOverflow` 则保持为 `UInt8`，该类型不足以存储结果——也就是说，发生了溢出。

```sql title="Query" theme={null}
CREATE TABLE sum_map
(
    `date` Date,
    `timeslot` DateTime,
    `statusMap` Nested(status UInt8, requests UInt8)
)
ENGINE = Log

INSERT INTO sum_map VALUES
    ('2000-01-01', '2000-01-01 00:00:00', [1, 2, 3], [10, 10, 10]),
    ('2000-01-01', '2000-01-01 00:00:00', [3, 4, 5], [10, 10, 10]),
    ('2000-01-01', '2000-01-01 00:01:00', [4, 5, 6], [10, 10, 10]),
    ('2000-01-01', '2000-01-01 00:01:00', [6, 7, 8], [10, 10, 10]);
```

```sql title="Query" theme={null}
SELECT sumMapFilteredWithOverflow([1, 4, 8])(statusMap.status, statusMap.requests) as summap_overflow, toTypeName(summap_overflow) FROM sum_map;
```

```sql title="Query" theme={null}
SELECT sumMapFiltered([1, 4, 8])(statusMap.status, statusMap.requests) as summap, toTypeName(summap) FROM sum_map;
```

```response title="Response" theme={null}
   ┌─sum──────────────────┬─toTypeName(sum)───────────────────┐
1. │ ([1,4,8],[10,20,10]) │ Tuple(Array(UInt8), Array(UInt8)) │
   └──────────────────────┴───────────────────────────────────┘
```

```response title="Response" theme={null}
   ┌─summap───────────────┬─toTypeName(summap)─────────────────┐
1. │ ([1,4,8],[10,20,10]) │ Tuple(Array(UInt8), Array(UInt64)) │
   └──────────────────────┴────────────────────────────────────┘
```

<div id="sequencenextnode">
  ## sequenceNextNode
</div>

返回与某个事件链匹配的下一个事件的值。

*Experimental 函数，设置 `SET allow_experimental_funnel_functions = 1` 以启用该函数。*

**语法**

```sql theme={null}
sequenceNextNode(direction, base)(timestamp, event_column, base_condition, event1, event2, event3, ...)
```

**参数**

* `direction` — 用于指定方向。
  * forward — 向前。
  * backward — 向后。

* `base` — 用于设置基准点。
  * head — 将基准点设为第一个事件。
  * tail — 将基准点设为最后一个事件。
  * first\_match — 将基准点设为第一个匹配的 `event1`。
  * last\_match — 将基准点设为最后一个匹配的 `event1`。

**Arguments**

* `timestamp` — 包含时间戳的列名。支持的数据类型：[Date](/zh/reference/data-types/date)、[DateTime](/zh/reference/data-types/datetime) 以及其他无符号整数类型。
* `event_column` — 包含要返回的下一个事件值的列名。支持的数据类型：[String](/zh/reference/data-types/string) 和 [Nullable(String)](/zh/reference/data-types/nullable)。
* `base_condition` — 基准点必须满足的条件。
* `event1`, `event2`, ... — 描述事件链的条件。[UInt8](/zh/reference/data-types/int-uint)。

**返回值**

* `event_column[next_index]` — 如果模式匹配且下一个值存在。
* `NULL` - 如果模式未匹配，或下一个值不存在。

类型：[Nullable(String)](/zh/reference/data-types/nullable)。

**示例**

当事件序列为 A->B->C->D->E，且你想知道 B->C 之后的事件 (即 D) 时，可以使用它。

用于查找 A->B 后续事件的查询语句：

```sql title="Query" theme={null}
CREATE TABLE test_flow (
    dt DateTime,
    id int,
    page String)
ENGINE = MergeTree()
PARTITION BY toYYYYMMDD(dt)
ORDER BY id;

INSERT INTO test_flow VALUES (1, 1, 'A') (2, 1, 'B') (3, 1, 'C') (4, 1, 'D') (5, 1, 'E');

SELECT id, sequenceNextNode('forward', 'head')(dt, page, page = 'A', page = 'A', page = 'B') as next_flow FROM test_flow GROUP BY id;
```

```text title="Response" theme={null}
┌─id─┬─next_flow─┐
│  1 │ C         │
└────┴───────────┘
```

**`forward` 和 `head` 的行为**

```sql theme={null}
ALTER TABLE test_flow DELETE WHERE 1 = 1 settings mutations_sync = 1;

INSERT INTO test_flow VALUES (1, 1, 'Home') (2, 1, 'Gift') (3, 1, 'Exit');
INSERT INTO test_flow VALUES (1, 2, 'Home') (2, 2, 'Home') (3, 2, 'Gift') (4, 2, 'Basket');
INSERT INTO test_flow VALUES (1, 3, 'Gift') (2, 3, 'Home') (3, 3, 'Gift') (4, 3, 'Basket');
```

```sql theme={null}
SELECT id, sequenceNextNode('forward', 'head')(dt, page, page = 'Home', page = 'Home', page = 'Gift') FROM test_flow GROUP BY id;

                  dt   id   page
 1970-01-01 09:00:01    1   Home // 基准点，与 Home 匹配
 1970-01-01 09:00:02    1   Gift // 与 Gift 匹配
 1970-01-01 09:00:03    1   Exit // 结果

 1970-01-01 09:00:01    2   Home // 基准点，与 Home 匹配
 1970-01-01 09:00:02    2   Home // 与 Gift 不匹配
 1970-01-01 09:00:03    2   Gift
 1970-01-01 09:00:04    2   Basket

 1970-01-01 09:00:01    3   Gift // 基准点，与 Home 不匹配
 1970-01-01 09:00:02    3   Home
 1970-01-01 09:00:03    3   Gift
 1970-01-01 09:00:04    3   Basket
```

**`backward` 和 `tail` 的行为**

```sql theme={null}
SELECT id, sequenceNextNode('backward', 'tail')(dt, page, page = 'Basket', page = 'Basket', page = 'Gift') FROM test_flow GROUP BY id;

                 dt   id   page
1970-01-01 09:00:01    1   Home
1970-01-01 09:00:02    1   Gift
1970-01-01 09:00:03    1   Exit // 基准点，未匹配到 Basket

1970-01-01 09:00:01    2   Home
1970-01-01 09:00:02    2   Home // 结果
1970-01-01 09:00:03    2   Gift // 匹配到 Gift
1970-01-01 09:00:04    2   Basket // 基准点，匹配到 Basket

1970-01-01 09:00:01    3   Gift
1970-01-01 09:00:02    3   Home // 结果
1970-01-01 09:00:03    3   Gift // 基准点, Matched with Gift
1970-01-01 09:00:04    3   Basket // 基准点，匹配到 Basket
```

**`forward` 和 `first_match` 的行为**

```sql theme={null}
SELECT id, sequenceNextNode('forward', 'first_match')(dt, page, page = 'Gift', page = 'Gift') FROM test_flow GROUP BY id;

                 dt   id   page
1970-01-01 09:00:01    1   Home
1970-01-01 09:00:02    1   Gift // 基准点
1970-01-01 09:00:03    1   Exit // 结果

1970-01-01 09:00:01    2   Home
1970-01-01 09:00:02    2   Home
1970-01-01 09:00:03    2   Gift // 基准点
1970-01-01 09:00:04    2   Basket  The result

1970-01-01 09:00:01    3   Gift // 基准点
1970-01-01 09:00:02    3   Home // 结果
1970-01-01 09:00:03    3   Gift
1970-01-01 09:00:04    3   Basket
```

```sql theme={null}
SELECT id, sequenceNextNode('forward', 'first_match')(dt, page, page = 'Gift', page = 'Gift', page = 'Home') FROM test_flow GROUP BY id;

                 dt   id   page
1970-01-01 09:00:01    1   Home
1970-01-01 09:00:02    1   Gift // 基准点
1970-01-01 09:00:03    1   Exit // 与 Home 不匹配

1970-01-01 09:00:01    2   Home
1970-01-01 09:00:02    2   Home
1970-01-01 09:00:03    2   Gift // 基准点
1970-01-01 09:00:04    2   Basket // 与 Home 不匹配

1970-01-01 09:00:01    3   Gift // 基准点
1970-01-01 09:00:02    3   Home // 与 Home 匹配
1970-01-01 09:00:03    3   Gift // 结果
1970-01-01 09:00:04    3   Basket
```

**`backward` 和 `last_match` 的行为**

```sql theme={null}
SELECT id, sequenceNextNode('backward', 'last_match')(dt, page, page = 'Gift', page = 'Gift') FROM test_flow GROUP BY id;

                 dt   id   page
1970-01-01 09:00:01    1   Home // 结果
1970-01-01 09:00:02    1   Gift // 基准点
1970-01-01 09:00:03    1   Exit

1970-01-01 09:00:01    2   Home
1970-01-01 09:00:02    2   Home // 结果
1970-01-01 09:00:03    2   Gift // 基准点
1970-01-01 09:00:04    2   Basket

1970-01-01 09:00:01    3   Gift
1970-01-01 09:00:02    3   Home // 结果
1970-01-01 09:00:03    3   Gift // 基准点
1970-01-01 09:00:04    3   Basket
```

```sql theme={null}
SELECT id, sequenceNextNode('backward', 'last_match')(dt, page, page = 'Gift', page = 'Gift', page = 'Home') FROM test_flow GROUP BY id;

                 dt   id   page
1970-01-01 09:00:01    1   Home // Matched with Home, the result is null
1970-01-01 09:00:02    1   Gift // 基准点
1970-01-01 09:00:03    1   Exit

1970-01-01 09:00:01    2   Home // The result
1970-01-01 09:00:02    2   Home // Matched with Home
1970-01-01 09:00:03    2   Gift // 基准点
1970-01-01 09:00:04    2   Basket

1970-01-01 09:00:01    3   Gift // 结果
1970-01-01 09:00:02    3   Home // 与 Home 匹配
1970-01-01 09:00:03    3   Gift // 基准点
1970-01-01 09:00:04    3   Basket
```

**`base_condition` 的行为**

```sql theme={null}
CREATE TABLE test_flow_basecond
(
    `dt` DateTime,
    `id` int,
    `page` String,
    `ref` String
)
ENGINE = MergeTree
PARTITION BY toYYYYMMDD(dt)
ORDER BY id;

INSERT INTO test_flow_basecond VALUES (1, 1, 'A', 'ref4') (2, 1, 'A', 'ref3') (3, 1, 'B', 'ref2') (4, 1, 'B', 'ref1');
```

```sql theme={null}
SELECT id, sequenceNextNode('forward', 'head')(dt, page, ref = 'ref1', page = 'A') FROM test_flow_basecond GROUP BY id;

                  dt   id   page   ref
 1970-01-01 09:00:01    1   A      ref4 // head 不能作为基准点，因为 head 的 ref 列与 'ref1' 不匹配。
 1970-01-01 09:00:02    1   A      ref3
 1970-01-01 09:00:03    1   B      ref2
 1970-01-01 09:00:04    1   B      ref1
```

```sql theme={null}
SELECT id, sequenceNextNode('backward', 'tail')(dt, page, ref = 'ref4', page = 'B') FROM test_flow_basecond GROUP BY id;

                  dt   id   page   ref
 1970-01-01 09:00:01    1   A      ref4
 1970-01-01 09:00:02    1   A      ref3
 1970-01-01 09:00:03    1   B      ref2
 1970-01-01 09:00:04    1   B      ref1 // tail 不能作为基准点，因为其 ref 列与 'ref4' 不匹配。
```

```sql theme={null}
SELECT id, sequenceNextNode('forward', 'first_match')(dt, page, ref = 'ref3', page = 'A') FROM test_flow_basecond GROUP BY id;

                  dt   id   page   ref
 1970-01-01 09:00:01    1   A      ref4 // 此行不能作为基准点，因为 ref 列与 'ref3' 不匹配。
 1970-01-01 09:00:02    1   A      ref3 // 基准点
 1970-01-01 09:00:03    1   B      ref2 // 结果
 1970-01-01 09:00:04    1   B      ref1
```

```sql theme={null}
SELECT id, sequenceNextNode('backward', 'last_match')(dt, page, ref = 'ref2', page = 'B') FROM test_flow_basecond GROUP BY id;

                  dt   id   page   ref
 1970-01-01 09:00:01    1   A      ref4
 1970-01-01 09:00:02    1   A      ref3 // 结果
 1970-01-01 09:00:03    1   B      ref2 // 基准点
 1970-01-01 09:00:04    1   B      ref1 // 此行不能作为基准点，因为 ref 列与 'ref2' 不匹配。
```
