在 Apache Doris 中,array_agg() 是聚合函数 ,用于将指定列的多行数据(通常配合 GROUP BY 使用)合并为一个数组(Array),是处理 "多行转单个数组" 场景的核心函数。以下从基础用法、语法规则、常见场景、注意事项等维度进行全面总结。
一、核心定义与语法
1. 功能定位
将 GROUP BY 分组后的某一列(或表达式结果)的所有非 NULL 值,按数据原始顺序(Doris 2.0+ 支持指定排序,旧版本依赖存储顺序)聚合为一个数组。
- 若分组内无数据或全为
NULL,返回空数组[](而非NULL)。 - 仅支持 Aggregate 聚合模型、Unique 模型、Duplicate 模型(所有 Doris 主流表模型)。
2. 语法格式
sql
array_agg(expr [ORDER BY sort_expr [ASC|DESC]] [SEPARATOR 'delimiter'])
| 参数 | 说明 |
|---|---|
expr |
必选,需聚合的列或表达式(支持数值、字符串、日期等 Doris 支持的基础类型)。 |
ORDER BY |
可选,指定数组内元素的排序规则(Doris 2.0+ 新增,旧版本无此功能)。 |
SEPARATOR |
可选,仅当 expr 为字符串类型时生效,指定数组转字符串时的分隔符(默认无)。 |
二、基础用法示例
假设存在表 student_score,存储学生的科目成绩,结构与数据如下:
| student_id | subject | score |
|---|---|---|
| 101 | Math | 90 |
| 101 | English | 85 |
| 101 | Chinese | 95 |
| 102 | Math | 78 |
| 102 | English | 88 |
| 103 | Math | NULL |
1. 基础聚合:分组合并为数组
按 student_id 分组,将每个学生的科目、成绩分别聚合为数组:
sql
SELECT
student_id,
array_agg(subject) AS subject_list, -- 字符串数组
array_agg(score) AS score_list -- 数值数组(自动过滤 NULL)
FROM student_score
GROUP BY student_id;
结果:
| student_id | subject_list | score_list | |
|---|---|---|---|
| 101 | ["Math","English","Chinese"] | [90,85,95] | |
| 102 | ["Math","English"] | [78,88] | |
| 103 | [] | [] | -- 无 subject 数据,返回空数组;score 为 NULL,也返回空数组 |
2. 带排序的聚合(Doris 2.0+)
按 student_id 分组,将成绩按降序聚合为数组(便于查看高分科目):
sql
SELECT
student_id,
array_agg(subject ORDER BY score DESC) AS subject_sorted_by_score,
array_agg(score ORDER BY score DESC) AS score_sorted
FROM student_score
GROUP BY student_id;
结果(101 学生的成绩降序排列):
| student_id | subject_sorted_by_score | score_sorted |
|---|---|---|
| 101 | ["Chinese","Math","English"] | [95,90,85] |
3. 字符串数组指定分隔符(SEPARATOR)
若需将字符串数组转为用特定符号分隔的字符串(如用 , 连接科目),可搭配 SEPARATOR:
sql
SELECT
student_id,
array_agg(subject SEPARATOR ',') AS subject_str -- 数组转字符串,用逗号分隔
FROM student_score
GROUP BY student_id;
结果:
| student_id | subject_str |
|---|---|
| 101 | Math,English,Chinese |
| 102 | Math,English |
三、进阶场景与组合用法
array_agg() 常与数组函数 (如 array_length()、array_contains())或窗口函数结合,实现更复杂的分析需求。
1. 统计数组长度(配合 array_length())
计算每个学生的考试科目数量(即数组的元素个数):
sql
SELECT
student_id,
array_agg(subject) AS subject_list,
array_length(array_agg(subject)) AS subject_count -- 统计数组长度
FROM student_score
GROUP BY student_id;
结果:
| student_id | subject_list | subject_count |
|---|---|---|
| 101 | ["Math","English","Chinese"] | 3 |
| 102 | ["Math","English"] | 2 |
2. 过滤数组元素(配合 array_filter())
聚合成绩后,过滤出分数 ≥ 90 的成绩(先聚合再过滤):
sql
SELECT
student_id,
array_filter(
array_agg(score), -- 待过滤的数组
x -> x >= 90 -- 过滤条件:元素 ≥ 90
) AS high_score_list
FROM student_score
GROUP BY student_id;
结果:
| student_id | high_score_list | |
|---|---|---|
| 101 | [90,95] | |
| 102 | [] | -- 无符合条件的成绩 |
| 103 | [] |
3. 窗口函数场景(不分组,保留原始行)
若需保留每一行数据,同时显示 "该学生的所有成绩"(不压缩行),可结合 OVER(PARTITION BY) 窗口:
sql
SELECT
student_id,
subject,
score,
array_agg(score) OVER (PARTITION BY student_id) AS all_scores_of_student
FROM student_score;
结果(101 学生的每一行都附带其所有成绩):
| student_id | subject | score | all_scores_of_student |
|---|---|---|---|
| 101 | Math | 90 | [90,85,95] |
| 101 | English | 85 | [90,85,95] |
| 101 | Chinese | 95 | [90,85,95] |
| 102 | Math | 78 | [78,88] |
四、关键注意事项
-
NULL值处理
array_agg()会自动过滤NULL值 ,即分组内若某行的expr为NULL,不会加入数组。例如 103 学生的score为NULL,聚合后score_list为空数组。 -
数据类型限制
- 支持聚合基础类型 (int、string、date、double 等),不支持聚合
Array、Map、Struct等复杂类型(即不能嵌套聚合array_agg(array_col))。 - 聚合后的数组元素类型与
expr类型一致(如expr为int,数组为Array<int>)。
- 支持聚合基础类型 (int、string、date、double 等),不支持聚合
-
排序功能的版本依赖
ORDER BY子句是 Doris 2.0 及以上版本新增的功能,旧版本(如 1.2、1.3)不支持,若需排序需先通过子查询排序,再聚合(但效果不稳定,建议升级版本)。 -
性能与数据量限制
- 若分组内数据量极大(如超过 10 万行),聚合后的数组会占用较多内存,可能导致查询性能下降,建议通过业务逻辑拆分分组。
- 数组元素个数无硬限制,但受 Doris 单条数据大小限制(默认单条数据不超过 100MB)。
-
与
group_concat()的区别-
array_agg()返回数组类型 ,可后续通过数组函数(如array_contains())进一步处理; -
group_concat()返回字符串类型,仅用于直接展示,无法后续解析元素。 -
示例对比: sql
array_agg(subject) → ["Math","English"] -- 数组 group_concat(subject, ',') → "Math,English" -- 字符串
-
五、常见问题排查
-
聚合后数组为空
- 原因:分组内无数据,或所有
expr均为NULL; - 排查:先执行
GROUP BY查看分组行数,确认是否有有效数据。
- 原因:分组内无数据,或所有
-
ORDER BY不生效- 原因:使用的 Doris 版本低于 2.0,或
ORDER BY后的字段未在expr中; - 解决:升级 Doris 版本,或确保
ORDER BY字段与expr逻辑一致。
- 原因:使用的 Doris 版本低于 2.0,或
-
数组元素顺序异常
- 原因:Doris 旧版本(<2.0)聚合顺序依赖数据存储顺序(非 SQL 执行顺序);
- 解决:升级到 2.0+ 版本,通过
ORDER BY显式指定顺序。
通过以上总结,可覆盖 array_agg() 在 Doris 中的绝大多数使用场景,结合实际业务需求(如多值聚合、数组过滤、窗口分析)灵活调用即可。