目录

clickhouse如何把两数组转为两列

在 clickhouse 中经常遇到把数组转为列的情况 .

一个数组转为列

一个数组转列的情况很简单 , 直接使用 arrayjoin 函数来实现

1
select arrayJoin([1,2,3,4]) n

/2020.9.4_clickhouse%E5%A6%82%E4%BD%95%E6%8A%8A%E4%B8%A4%E6%95%B0%E7%BB%84%E8%BD%AC%E4%B8%BA%E4%B8%A4%E5%88%97/image-20200904154153887.png

两个数组转为两列遇到的问题

现有两个数组 , 想要把这两个数组转为两列 . 比如

/2020.9.4_clickhouse%E5%A6%82%E4%BD%95%E6%8A%8A%E4%B8%A4%E6%95%B0%E7%BB%84%E8%BD%AC%E4%B8%BA%E4%B8%A4%E5%88%97/image-20200911165627074.png 变为 /2020.9.4_clickhouse%E5%A6%82%E4%BD%95%E6%8A%8A%E4%B8%A4%E6%95%B0%E7%BB%84%E8%BD%AC%E4%B8%BA%E4%B8%A4%E5%88%97/image-20200911165722019.png

按照上面的经验分别对这两个数组使用 arrayjoin , 但是结果明显不符合我预期

1
2
3
with [1,2,3,4] as number,
    ['a','b','c','d'] as str
select arrayJoin(number) n, arrayJoin(str) s;

/2020.9.4_clickhouse%E5%A6%82%E4%BD%95%E6%8A%8A%E4%B8%A4%E6%95%B0%E7%BB%84%E8%BD%AC%E4%B8%BA%E4%B8%A4%E5%88%97/image-20200911170248197.png

clickhouse 明显是把两列做了笛卡尔积

解决问题

这时可以用 clickhouse 的高级函数 arraymaptuple 配合来实现这个变换

arraymap 的效果和 java8 里的 map 是一样的 . 即对数组的每一个元素做处理然后返回一个新的数组

/2020.9.4_clickhouse%E5%A6%82%E4%BD%95%E6%8A%8A%E4%B8%A4%E6%95%B0%E7%BB%84%E8%BD%AC%E4%B8%BA%E4%B8%A4%E5%88%97/image-20200911171039087.png

上图就是对 [1,2,3] 数组进行加一 , 然后返回 [2,3,4]

tuple 里可以装不同类型的数据 , 下图就是把一个 int 和一个 string 放在了一个 tuple

/2020.9.4_clickhouse%E5%A6%82%E4%BD%95%E6%8A%8A%E4%B8%A4%E6%95%B0%E7%BB%84%E8%BD%AC%E4%B8%BA%E4%B8%A4%E5%88%97/image-20200911171309314.png

关于 tuple 更多的操作可以查阅官方文档

arrymap 不光可以对一个数组进行操作 , 还可以把不同的数组放到一个 tuple 数组中 . 官方文档的示例如下 :

/2020.9.4_clickhouse%E5%A6%82%E4%BD%95%E6%8A%8A%E4%B8%A4%E6%95%B0%E7%BB%84%E8%BD%AC%E4%B8%BA%E4%B8%A4%E5%88%97/image-20200911172215792.png

这种方法就能实现我们的目标

/2020.9.4_clickhouse%E5%A6%82%E4%BD%95%E6%8A%8A%E4%B8%A4%E6%95%B0%E7%BB%84%E8%BD%AC%E4%B8%BA%E4%B8%A4%E5%88%97/image-20200911172314295.png

\

tuple.1 就是引用 tuple 内第一个元素 , 这里也看出 clickhouse 的索引下标是从 1 开始的

结果

最后结果就是通过 arraymap 和 tuple 配合来实现

sql 如下

1
2
3
4
5
with [1,2,3,4] as number,
    ['a','b','c','d'] as str
select arrayJoin(arrayMap((x, y)-> (x, y), number, str)) tuple,
       tuple.1                                           n,
       tuple.2                                           s;