Mysql中GROUP_CONCAT分组聚合函数的使用以及示例
一、函数定义与基础语法
GROUP_CONCAT(
[DISTINCT] 字段名
[ORDER BY 排序字段 [ASC|DESC]]
[SEPARATOR '分隔符']
)
默认行为:连接非NULL值,默认逗号分隔
长度限制:受group_concat_max_len控制(默认1024字节)
二、核心使用场景与示例
1. 基础字符串连接
-- 连接部门所有员工姓名
SELECTdept_id,GROUP_CONCAT(employee_name) AS members
FROM employees
GROUP BY dept_id;
输出示例:
| dept_id | members |
|---------|------------------|
| 1 | 张三,李四,王五 |
2. 去重连接(DISTINCT)
-- 连接不重复的城市名
SELECTcountry,GROUP_CONCAT(DISTINCT city) AS cities
FROM locations
GROUP BY country;
3. 自定义排序(ORDER BY)
-- 按入职时间倒序连接
SELECTdept_id,GROUP_CONCAT(employee_nameORDER BY hire_date DESCSEPARATOR ' | ') AS seniority_list
FROM employees
GROUP BY dept_id;
4. 多字段组合
-- 连接姓名+工号
SELECTproject_id,GROUP_CONCAT(CONCAT(name,'(',emp_id,')')SEPARATOR '; ') AS project_team
FROM project_members
GROUP BY project_id;
三、高级应用技巧
1. 处理NULL值
-- 跳过NULL值(默认行为)
GROUP_CONCAT(IFNULL(field, 'N/A'))-- 包含NULL占位
GROUP_CONCAT(field SEPARATOR '|')
2. 动态设置长度
-- 会话级调整(最大1MB)
SET SESSION group_concat_max_len = 1024 * 1024;
3. 嵌套JSON输出(MySQL 8.0+)
SELECTdept_id,JSON_ARRAYAGG(JSON_OBJECT('name', name, 'id', emp_id)) AS member_json
FROM employees
GROUP BY dept_id;
4. 与CONCAT_WS配合
-- 智能处理空值
SELECTGROUP_CONCAT(CONCAT_WS(':',NULLIF(first_name,''),NULLIF(last_name,''))SEPARATOR '\n') AS full_names
FROM users;
五、业务使用示例
<select id= "pageAlarmEvent" resultMap= "PageResultMap">selectae.id,ae.event_name,ae.rule_name,ae.monitoring,ae.warehouse_id,ae.level,ar.time_interval,GROUP_CONCAT(an.title ORDER BY aen.id SEPARATOR ', ') AS notificationIdList,ae.notification_time,ae.start_time,ae.end_time,ae.is_next,ae.event_status,ae.update_user_id,ae.update_timeFROMalarm_event aeLEFT JOINalarm_rule ar ON ae.rule_id = ar.idLEFT JOINalarm_event_notification aen ON ae.id = aen.event_id and aen.is_delete = 0LEFT JOINalarm_notification an ON aen.notification_id = an.id<where>ae.is_delete = 0AND ae.company_id=#{companyId}<!-- 添加筛选条件 --><if test="queryParam.warehouseId != null and queryParam.warehouseId != ''">AND ae.warehouse_id = #{queryParam.warehouseId}</if><if test="queryParam.tankId != null">AND ae.tank_id = #{queryParam.tankId}</if><if test="queryParam.level != null">AND ae.level = #{queryParam.level}</if><if test="queryParam.eventName != null and queryParam.eventName != ''">AND ae.event_name LIKE CONCAT('%', #{queryParam.eventName}, '%')</if><if test="queryParam.eventStatus != null">AND ae.event_status = #{queryParam.eventStatus}</if></where>GROUP BYae.id,ae.event_name,ae.rule_name,ae.monitoring,ae.level,ae.warehouse_id,ar.time_interval,ae.notification_time,ae.start_time,ae.end_time,ae.is_next,ae.event_status,ae.update_user_id,ae.update_time<!-- 添加排序条件 -->ORDER BY ae.update_time DESC</select>
场景描述
某告警事件ID= "event_123"关联了3条通知:
aen.id an.title
88 温度过高
92 压力异常
95 阀门泄漏
执行过程
按aen.id 排序得到序列:88 → 92 → 95
提取对应an.title :温度过高 → 压力异常 → 阀门泄漏
用分隔符连接:"温度过高, 压力异常, 阀门泄漏"
最终结果
{
"id": "event_123",
"notificationIdList": "温度过高, 压力异常, 阀门泄漏"
}