跳到主要内容
跳到主要内容

ARRAY JOIN 子句

对于包含数组列的表,生成一个新表的操作是很常见的,该新表的每一行都包含初始列的每个单独数组元素,而其他列的值则被重复。这就是 ARRAY JOIN 子句的基本情况。

其名称源于可以将其视为与数组或嵌套数据结构执行 JOIN。其意图与 arrayJoin 函数相似,但该子句的功能更广泛。

语法:

支持的 ARRAY JOIN 类型如下所示:

  • ARRAY JOIN - 在基本 case 下,空数组不包含在 JOIN 的结果中。
  • LEFT ARRAY JOIN - JOIN 的结果包含带有空数组的行。空数组的值设置为数组元素类型的默认值(通常为 0、空字符串或 NULL)。

基本 ARRAY JOIN 示例

ARRAY JOIN 和 LEFT ARRAY JOIN

下面的示例展示了 ARRAY JOINLEFT ARRAY JOIN 子句的用法。让我们创建一个包含 Array 类型列的表并插入值:

下面的示例使用 ARRAY JOIN 子句:

下一个示例使用 LEFT ARRAY JOIN 子句:

ARRAY JOIN 和 arrayEnumerate 函数

该函数通常与 ARRAY JOIN 一起使用。它允许在应用 ARRAY JOIN 后仅对每个数组计数一次。示例:

在此示例中,Reaches 是转换的数量(在应用 ARRAY JOIN 后接收到的字符串),而 Hits 是页面浏览量(在 ARRAY JOIN 之前的字符串)。在此特定情况下,您可以更简单地获得相同的结果:

ARRAY JOIN 和 arrayEnumerateUniq

在使用 ARRAY JOIN 和聚合数组元素时,此函数非常有用。

在此示例中,每个目标 ID 都计算了转换的数量(Goals 嵌套数据结构中的每个元素是一个达成的目标,我们称之为转换)和会话数量。如果没有 ARRAY JOIN,我们将会话数量计算为 sum(Sign)。但在此特定情况下,行数是由嵌套 Goals 结构乘以的,因此为了在这之后计算每个会话一次,我们对 arrayEnumerateUniq(Goals.ID) 函数的值应用条件。

使用别名

可以为 ARRAY JOIN 子句中的数组指定别名。在这种情况下,可以通过该别名访问数组项目,但数组本身仍通过原始名称访问。示例:

使用别名,您可以通过外部数组执行 ARRAY JOIN。例如:

ARRAY JOIN 子句中,可以用逗号分隔多个数组。在这种情况下,会同时对它们执行 JOIN(直接和,而不是笛卡尔积)。请注意,默认情况下,所有数组必须具有相同的大小。示例:

下面的示例使用 arrayEnumerate 函数:

可以通过使用:SETTINGS enable_unaligned_array_join = 1 将不同大小的多个数组连接起来。示例:

ARRAY JOIN 与嵌套数据结构

ARRAY JOIN 同样适用于 嵌套数据结构

ARRAY JOIN 中指定嵌套数据结构的名称时,含义与其包含的所有数组元素的 ARRAY JOIN 相同。下面列出了示例:

这个变体也有意义:

可以为嵌套数据结构使用别名,以选择要么 JOIN 的结果,要么源数组。示例:

使用 arrayEnumerate 函数的示例:

实现细节

在运行 ARRAY JOIN 时,查询执行顺序是优化的。虽然 ARRAY JOIN 必须始终在查询中指定在 WHERE/PREWHERE 子句之前,但从技术上讲,它们可以以任何顺序执行,除非 ARRAY JOIN 的结果用于过滤。处理顺序由查询优化器控制。

与短路函数求值的不兼容性

短路函数求值 是一种优化特定函数(如 ifmultiIfandor)中复杂表达式执行的特性。它防止在执行这些函数的过程中出现潜在异常,例如除以零。

arrayJoin 始终被执行,并且不支持短路函数求值。这是因为它是一个独特的函数,在查询分析和执行中与所有其他函数分开处理,并且需要额外的逻辑,这与短路函数执行不兼容。原因在于,结果中的行数取决于 arrayJoin 的结果,懒惰地执行 arrayJoin 实现起来太复杂且成本太高。