




arrayJoin后不能直接GROUP BY,因为它是表函数,会将一行展开为多行,未出现在GROUP BY中的非聚合列会导致ClickHouse报错;必须用ARRAY JOIN子句或子查询显式展开数组。
因为 arrayJoin 是表函数,不是普通函数,它会把一行“炸开”成多行,原始行的其他列会被复制。如果你在 SELECT 中用了 arrayJoin,又没把它放进 GROUP BY,ClickHouse 会报错:Column 'xxx' is not under aggregate function and not in GROUP BY。这不是语法限制,而是语义要求:每行输出必须能被明确归组。
常见错误写法:
SELECT arrayJoin(tags) AS tag, count() FROM events GROUP BY tag
看着对,但实际会失败——arrayJoin(tags) 不是列名,不能直接 GROUP BY;必须先用 ARRAY JOIN 子句或子查询显式展开。
推荐优先用 ARRAY JOIN 语法,清晰、高效、兼容性好(所有 ClickHouse 版本都支持):
ARRAY JOIN 必须写在 FROM 子句之后,它会为数组中每个元素生成一行,并保留原表其他字段tag)可直接用于 SELECT 和 GROUP BY
LEFT ARRAY JOIN
示例(统计每个 tag 出现次数):
SELECT tag, count() FROM events ARRAY JOIN tags AS tag GROUP BY tag
等价的子查询写法(适合嵌套逻辑或需要多次引用展开结果):
SELECT tag, count() FROM (SELECT *, arrayJoin(tags) AS tag FROM events) GROUP BY tag
关键看你要统计什么:
count() 或 count(DISTINCT event_id)(如果事件有唯一 ID)count(),因为 ARRAY JOIN 已按元素展开tags = ['a','a','b'],默认会展开为三行,count() 结果里 a 就是 2 次——这是预期行为;若要去重,得先用 arrayDistinct
去重后统计(每个事件内 tag 去重再展开):
SELECT tag, count() FROM events ARRAY JOIN arrayDistinct(tags) AS tag GROUP BY tag
ARRAY JOIN 本身不慢,但容易引发数据膨胀。比如平均一个事件带 10 个 tag,100 万行就变成 1000 万行处理。这时候:
WHERE 过滤再 ARRAY JOIN,别在展开后才过滤[] 同样被跳过;需要补零行,用 LEFT ARRAY JOIN + ifNull
GROUP BY 会把 NULL 当作一个独立分组补 NULL 分组的写法(让空/NULL tag 显式归为 '[null]'):
SELECTifNull(tag, '[null]') AS tag, count() FROM events LEFT ARRAY JOIN tags AS tag GROUP BY tag
真正容易被忽略的是:ARRAY JOIN 不支持嵌套数组(如 Array(Array(String))),要 flatten 得靠 arrayFlatten 配合两次 arrayJoin。这步一旦漏掉,聚合结果就少了一层维度。