在 Doris 中,GROUP_CONCAT 是常用的聚合函数,用于将分组内某列的多个值拼接成一个字符串。它支持通过 ORDER BY 对拼接的元素排序,通过 SEPARATOR 指定元素间的分隔符(默认分隔符为英文逗号 ,)。以下从基础语法、核心用法(含排序 + 自定义分隔符)、注意事项、常见场景四个维度进行总结,确保覆盖实际开发中的高频需求。
一、基础语法
Doris 中 GROUP_CONCAT 的完整语法格式如下(兼容 MySQL 语法,降低学习成本):
sql
GROUP_CONCAT(
[DISTINCT] -- 可选,去重后再拼接
列名/表达式 -- 必选,需拼接的列或计算表达式(如 IF、CASE 结果)
[ORDER BY 排序列 [ASC/DESC]] -- 可选,对拼接的元素排序
[SEPARATOR '分隔符'] -- 可选,指定元素间的分隔符(默认是 ',')
)
关键参数说明
| 参数 | 作用 | 是否必选 | |
|---|---|---|---|
列名/表达式 | 指定分组内需要拼接的数据来源(如某列值、或 IF(status=1, '正常', '异常') 这类计算结果) | 是 | |
DISTINCT | 可选,对拼接的元素去重(例如同一分组内有重复值,只保留一个) | 否 | |
ORDER BY 排序列 | 可选,对分组内待拼接的元素按指定列排序(确保拼接结果的顺序可预期) | 否 | |
SEPARATOR '分隔符' | 可选,指定元素间的分隔符(如 `' | '、'-'、空字符串 ''等),默认是','` | 否 |
二、核心用法总结(含示例)
以下示例基于一张模拟的 user_orders 表(数据如下),覆盖 GROUP_CONCAT 与 ORDER BY、SEPARATOR 的组合用法:
| user_id | order_id | order_date | product_name | amount |
|---|---|---|---|---|
| 101 | 5001 | 2024-05-01 | 手机 | 3999 |
| 101 | 5003 | 2024-05-03 | 耳机 | 299 |
| 101 | 5002 | 2024-05-02 | 充电器 | 89 |
| 102 | 5004 | 2024-05-01 | 键盘 | 199 |
| 102 | 5005 | 2024-05-02 | 鼠标 | 99 |
1. 基础用法:默认分隔符(无排序)
不指定 ORDER BY 和 SEPARATOR,默认按数据存储顺序拼接,分隔符为 ,。
需求:按 user_id 分组,拼接每个用户的订单 ID。
sql
SELECT
user_id,
GROUP_CONCAT(order_id) AS order_id_list -- 默认用 ',' 拼接,无排序
FROM user_orders
GROUP BY user_id;
结果(注意:101 的订单 ID 顺序未排序,与存储顺序一致):
| user_id | order_id_list |
|---|---|
| 101 | 5001,5003,5002 |
| 102 | 5004,5005 |
2. 结合 ORDER BY:按指定字段排序后拼接
实际场景中,常需要按时间、数值等排序后拼接(如按订单日期升序),确保结果顺序可预期。
需求:按 user_id 分组,按 order_date 升序拼接每个用户的 “订单 ID - 商品名”。
sql
SELECT
user_id,
-- 拼接格式:order_id-product_name,按 order_date 升序排序
GROUP_CONCAT(
CONCAT(order_id, '-', product_name) -- 自定义拼接元素格式
ORDER BY order_date ASC -- 按订单日期升序
) AS order_product_list
FROM user_orders
GROUP BY user_id;
结果(101 的订单按日期从早到晚排序,5001→5002→5003):
| user_id | order_product_list |
|---|---|
| 101 | 5001 - 手机,5002 - 充电器,5003 - 耳机 |
| 102 | 5004 - 键盘,5005 - 鼠标 |
3. 结合 SEPARATOR:自定义分隔符
默认分隔符是 ,,可通过 SEPARATOR 指定其他分隔符(如 |、-、空字符串等)。
需求:按 user_id 分组,用 | 分隔符拼接商品名,且按金额降序排序。
sql
SELECT
user_id,
GROUP_CONCAT(
product_name
ORDER BY amount DESC -- 按订单金额降序(手机>耳机>充电器)
SEPARATOR '|' -- 自定义分隔符为 '|'
) AS product_list_by_amount
FROM user_orders
GROUP BY user_id;
结果(101 的商品按金额从高到低排序,分隔符为 |):
| user_id | product_list_by_amount | ||
|---|---|---|---|
| 101 | 手机 | 耳机 | 充电器 |
| 102 | 键盘 | 鼠标 |
4. 含 DISTINCT:去重后拼接
若分组内某列有重复值(如同一用户多次购买同一商品),可通过 DISTINCT 去重后再拼接。
需求:按 user_id 分组,去重后拼接用户购买的商品类别(假设新增 category 列,存在重复)。
sql
-- 模拟表新增 category 列后的数据(101重复购买“数码”类商品)
SELECT
user_id,
GROUP_CONCAT(
DISTINCT category -- 去重:同一类别只保留一次
ORDER BY category ASC
SEPARATOR '-'
) AS distinct_category
FROM user_orders
GROUP BY user_id;
结果(101 的 “数码” 类别去重后只出现一次):
| user_id | distinct_category |
|---|---|
| 101 | 数码 - 配件 |
| 102 | 外设 |
5. 空字符串分隔符(无缝拼接)
若需要拼接后无分隔符(如将数值拼接成一串数字),可指定 SEPARATOR ''(空字符串)。
需求:按 user_id 分组,将订单金额按日期升序无缝拼接(如 399929989)。
sql
SELECT
user_id,
GROUP_CONCAT(
amount
ORDER BY order_date ASC
SEPARATOR '' -- 空分隔符,无缝拼接
) AS amount_concat
FROM user_orders
GROUP BY user_id;
结果(101 的金额按日期拼接为 3999(5.1)+89(5.2)+299(5.3)= 399989299):
| user_id | amount_concat |
|---|---|
| 101 | 399989299 |
| 102 | 19999 |
三、注意事项(避坑指南)
-
必须搭配
GROUP BY
GROUP_CONCAT是聚合函数,不能单独使用,必须配合GROUP BY指定分组字段(除非仅聚合全表数据,此时GROUP BY可省略,但不推荐,可读性差)。
❌ 错误示例(无GROUP BY,全表聚合,仅返回 1 行):sql
SELECT GROUP_CONCAT(product_name); -- 不推荐,需明确分组逻辑✅ 正确示例(按
user_id分组):sql
SELECT user_id, GROUP_CONCAT(product_name) FROM user_orders GROUP BY user_id; -
排序字段需在分组上下文内
ORDER BY后指定的 “排序列”,必须是 分组字段、聚合列、或原始表中存在的列(不能是其他未关联的列)。
❌ 错误示例(排序列other_col不在表中):sql
SELECT user_id, GROUP_CONCAT(product_name ORDER BY other_col) FROM user_orders GROUP BY user_id; -
结果长度限制(默认 1024 字符)
Doris 中GROUP_CONCAT的默认结果长度限制为 1024 个字符,若拼接后字符串超长,会被截断(导致数据丢失)。- 查看当前限制:执行
SHOW VARIABLES LIKE 'group_concat_max_len'; - 临时调整限制(会话级):执行
SET group_concat_max_len = 102400;(设置为 100KB,根据需求调整) - 永久调整:需在 Doris 配置文件中修改
group_concat_max_len参数(需重启服务)。
- 查看当前限制:执行
-
NULL 值处理
若待拼接的列包含NULL,GROUP_CONCAT会自动忽略NULL值(不拼接NULL,也不会用分隔符填充)。
示例:若某用户的product_name有NULL,拼接结果会跳过该值:sql
-- 假设 user_id=101 有一条 product_name=NULL 的数据 SELECT user_id, GROUP_CONCAT(product_name) FROM user_orders GROUP BY user_id; -- 结果:101 → 手机,耳机,充电器(NULL被忽略) -
与
CASE/IF结合的表达式拼接
支持拼接 “条件表达式” 的结果(如将状态值转为文字后拼接),语法上直接将表达式作为GROUP_CONCAT的参数即可。
示例:拼接订单状态(1 = 已支付,0 = 未支付):sql
SELECT user_id, GROUP_CONCAT( IF(status=1, '已支付', '未支付') -- 条件表达式 ORDER BY order_date SEPARATOR '|' ) AS order_status_list FROM user_orders GROUP BY user_id;
四、常见业务场景
| 场景 | 实现 SQL 示例 | |
|---|---|---|
| 拼接用户的所有订单号 | SELECT user_id, GROUP_CONCAT(order_id SEPARATOR ',') FROM orders GROUP BY user_id; | |
| 按时间排序拼接操作日志 | SELECT user_id, GROUP_CONCAT(log_content ORDER BY log_time SEPARATOR ';') FROM logs GROUP BY user_id; | |
| 去重拼接用户标签 | `SELECT user_id, GROUP_CONCAT(DISTINCT tag SEPARATOR ' | ') FROM user_tags GROUP BY user_id;` |
| 无缝拼接数值成编码 | SELECT dept_id, GROUP_CONCAT(emp_id ORDER BY emp_id SEPARATOR '') FROM employees GROUP BY dept_id; |
总结
Doris 中的 GROUP_CONCAT 核心能力是 “分组拼接”,通过 ORDER BY 确保拼接顺序可控,通过 SEPARATOR 自定义分隔符,配合 DISTINCT 可实现去重拼接。实际使用时需注意 分组逻辑、结果长度限制、NULL 值处理,避免因语法或配置问题导致数据异常。

4252

被折叠的 条评论
为什么被折叠?



