You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ClickHouse中按A分组且按B/C等任意列匹配分组的实现技巧

ClickHouse多列关联分组实现方案

问题场景

现有如下数据表:

┌─A─┬─B─┬─C─┐
│ 1 │ 1 │ 1 │
│ 1 │ 2 │ 1 │
│ 1 │ 3 │ 3 │
└───┴───┴───┘

需要实现的分组逻辑:按A分组的同时,若行与行之间在B、C(或更多列)中任意一列的值相同,则归为同一组。期望实现类似如下逻辑的查询:

select A, groupArray(B) as B, groupArray(C) as C
from test
group by A and (B or C)

预期查询结果:

┌─A─┬─B----─┬─C─----┐
│ 1 │ [1,2] │ [1,1] │  // A和C匹配对应前两行
│ 1 │ [3]   │ [3]   │  // A匹配但B和C均不匹配对应第三行
└───┴──----─┴──----─┘

建表与插入数据的脚本:

create table tests
(
    A UInt64,
    B UInt64,
    C UInt64
)
    engine = Memory;

insert into tests (A, B, C)
values (1, 1, 1),
       (1, 2, 1),
       (1, 3, 3);

实现方案

可以利用ClickHouse的connectedComponents函数识别连通分量,将满足条件的行归为同一组。核心思路是:同一A值的行中,只要在B或C列有相同值,就视为同一连通组,再按A和连通组ID分组聚合。

查询脚本如下:

WITH
    rowNumberInAllBlocks() AS row_id,
    -- 生成同一A下,B或C值相同的行关联关系
    arrayConcat(
        arrayMap(x -> (row_id, x), (SELECT groupArray(row_id) FROM tests WHERE A = t.A AND B = t.B)),
        arrayMap(x -> (row_id, x), (SELECT groupArray(row_id) FROM tests WHERE A = t.A AND C = t.C))
    ) AS edges,
    arrayJoin(edges) AS edge,
    connectedComponents(edge.1, edge.2) AS component_id
SELECT
    A,
    groupArray(B) AS B,
    groupArray(C) AS C
FROM tests t
GROUP BY A, component_id
ORDER BY A, component_id;

扩展说明

如果需要支持更多列(如D、E等),只需在arrayConcat中添加对应列的关联逻辑即可,示例如下:

arrayConcat(
    arrayMap(x -> (row_id, x), (SELECT groupArray(row_id) FROM tests WHERE A = t.A AND B = t.B)),
    arrayMap(x -> (row_id, x), (SELECT groupArray(row_id) FROM tests WHERE A = t.A AND C = t.C)),
    arrayMap(x -> (row_id, x), (SELECT groupArray(row_id) FROM tests WHERE A = t.A AND D = t.D))
    -- 继续添加更多列的关联规则
)

内容的提问来源于stack exchange,提问作者Oleg

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 11:35:13