在 ​ClickHouse​ 中,​Array(T)类型​ 是一种非常常用的 ​复合数据类型,用来存储 ​相同类型的元素的有序集合(即数组)​,比如:

  • 一个用户有多个标签 → Array(String),如 ['tag1', 'tag2', 'tag3']

  • 一个订单包含多个商品 ID → Array(UInt32),如 [1001, 1002, 1003]

  • 一个设备上报了多个数值指标 → Array(Float64)

1. ​语法:​

Array(T)
  • ​T​ 是数组中元素的类型,比如:

    • Int32

    • String

    • Float64

    • 自定义类型,甚至是 Nested、Tuple等

  • ​Array(T)​ 表示一个元素类型为 T的数组

2. ​示例:建表时使用 Array 类型字段

CREATE TABLE example (
    id UInt32,
    tags Array(String),           -- 字符串数组,如 ['a', 'b', 'c']
    scores Array(Float64),        -- 浮点数数组,如 [95.5, 88.0, 91.2]
    counts Array(UInt32)          -- 整数数组,如 [1, 2, 3]
) ENGINE = MergeTree()
ORDER BY id;

✅ 二、Array 类型常见用途

场景

说明

示例

​标签 / 分类信息​

一个实体有多个标签,如用户标签、商品类目

tags Array(String)

​多值属性​

比如一个订单有多个商品 ID、一个用户有多个设备 ID

items Array(UInt32)

​时间序列 / 指标数据​

某个时间段内采集的多个数值

values Array(Float64)

​嵌套结构简化​

在不用 Nested类型时,用多个平行数组表示关联数据

比如 names Array(String), ages Array(UInt8)


✅ 三、如何插入 Array 类型的数据?

在插入数据时,ClickHouse 支持用 ​方括号 []​ 来直接表示数组。

✅ 示例:插入数据

INSERT INTO example (id, tags, scores, counts) VALUES
(1, ['tag1', 'tag2'], [95.5, 89.0], [1, 2]),
(2, ['tag3', 'tag4', 'tag5'], [91.0, 87.5, 90.0], [3, 4, 5]);

🔍 说明:

  • tags是一个字符串数组

  • scores是一个浮点数数组

  • counts是一个整数数组


✅ 四、如何查询 Array 类型字段?

1. ​直接查询数组字段(原样展示)​

SELECT id, tags FROM example;

输出类似:

┌─id─┬─tags───────────┐
│  1 │ ['tag1','tag2']│
│  2 │ ['tag3','tag4','tag5'] │
└────┴────────────────┘

2. ​查询数组长度(元素个数):使用 length()函数

SELECT id, length(tags) AS tag_count FROM example;

输出:

┌─id─┬─tag_count─┐
│  1 │         2 │
│  2 │         3 │
└────┴───────────┘

3. ​访问数组中的某个元素:使用 arrayElement(arr, index)或 arr[index]​

索引从 ​1 开始​(不是 0!)

SELECT 
    id, 
    tags[1] AS first_tag,
    scores[2] AS second_score
FROM example;

输出:

┌─id─┬─first_tag─┬─second_score─┐
│  1 │ tag1      │         89.0 │
│  2 │ tag3      │         87.5 │
└────┴───────────┴──────────────┘

✅ 五、常用 Array 函数(ClickHouse 提供了很多!)

函数

说明

示例

​length(array)​

返回数组长度(元素个数)

length(tags)

​arrayElement(array, n)​ 或 ​array[n]​

获取第 n 个元素(从 1 开始)

tags[1]

​has(array, value)​

判断数组是否包含某个值

has(tags, 'tag1')→ true/false

​arrayJoin(array)​

将数组展开为多行(常用于展开数组后关联查询)

详见下文

​arrayConcat(array1, array2)​

拼接多个数组

arrayConcat([1,2], [3]) => [1,2,3]

​arrayContains(array, x)​

是否包含某个值(同 has)

​arraySort(array)​

对数组排序

arraySort([3,1,2]) => [1,2,3]

​arrayDistinct(array)​

去重

arrayDistinct([1,2,2]) => [1,2]

​arraySum(array)​

求数组数值元素之和(仅数值类型)

arraySum([1,2,3]) => 6

​arrayAvg(array)​

平均值

仅适用于数值类型

​arrayMin(array)/ arrayMax(array)​

最小值 / 最大值


✅ 六、高级用法:arrayJoin(数组展开为多行)

如果你想把一个数组字段的每个元素拆成 ​多行​(一行变多行,每个元素一行),可以使用 arrayJoin函数。

✅ 示例:

SELECT 
    id, 
    arrayJoin(tags) AS single_tag
FROM example;

假设原数据:

id | tags
---|-----------
1  | ['a', 'b']
2  | ['x', 'y', 'z']

输出结果为:

┌─id─┬─single_tag─┐
│  1 │ a          │
│  1 │ b          │
│  2 │ x          │
│  2 │ y          │
│  2 │ z          │
└────┴────────────┘

🔍 ​用途:​​

  • 用于数组展开后与其他表做 ​JOIN​

  • 用于分析数组中的每个元素

  • 用于生成多行明细


✅ 七、在 WHERE 子句中过滤数组

你可以使用以下方式对数组字段进行过滤:

1. ​判断数组是否包含某个值:has(array, value)

SELECT * FROM example WHERE has(tags, 'tag1');

2. ​判断数组长度:length(array) > 0

SELECT * FROM example WHERE length(tags) > 0;

3. ​结合 AND / OR 复杂条件​


✅ 八、在 ORDER BY / GROUP BY 中使用 Array

  • ​GROUP BY数组字段本身通常无意义(数组是集合,不是标量)​​

  • 但你可以:

    • 使用 arrayJoin展开后再 GROUP BY

    • 或者使用 arrayReduce等聚合函数对数组内容做聚合


✅ 九、Array 与 JSON 的对比

特性

Array(T)(ClickHouse)

JSON(如 String 类型存储 JSON 数组)

类型安全

✅ 是,数组元素类型固定为 T

❌ 否,JSON 是文本,类型不安全

查询效率

✅ 高,ClickHouse 对 Array 有原生优化

❌ 较低,需用 JSON 函数解析

灵活性

❌ 元素类型固定

✅ 可存储任意结构

推荐使用场景

明确知道是同类型元素的集合,如标签、数值列表

存储异构、灵活结构,如配置、元数据


✅ 十、总结:ClickHouse 的 Array 类型

项目

说明

​定义方式​

Array(T),T 为元素类型,如 Array(String)、Array(Int32)

​用途​

存储一组相同类型的值,如标签、列表、多值属性等

​插入方式​

直接用 []表示,如 ['a', 'b']、[1, 2, 3]

​查询支持​

提供丰富函数:length()、has()、arrayElement()、arrayJoin()等

​展开数组​

使用 arrayJoin(array)将数组转为多行

​性能​

ClickHouse 对 Array 类型有原生优化,查询效率高

​常见场景​

用户标签、商品 SKU 列表、日志中的多个数值、维度展开等


✅ 附:建表示例 + 插入 + 查询 综合案例

-- 1. 建表
CREATE TABLE user_tags (
    user_id UInt32,
    tags Array(String),
    scores Array(Float64)
) ENGINE = MergeTree()
ORDER BY user_id;

-- 2. 插入数据
INSERT INTO user_tags VALUES
(1, ['music', 'sports'], [9.5, 8.0]),
(2, ['books', 'travel', 'food'], [9.0, 9.5, 8.5]),
(3, ['tech'], [10.0]);

-- 3. 查询
SELECT 
    user_id,
    tags,
    length(tags) AS tag_count,
    tags[1] AS first_tag
FROM user_tags;

-- 4. 展开数组(每个标签一行)
SELECT 
    user_id,
    arrayJoin(tags) AS tag
FROM user_tags;

更多推荐