GROUP_CONCAT必须显式使用DISTINCT才能去重,且DISTINCT必须置于ORDER BY之前;默认不自动去重,超长(1024字节)会静默截断,需调大group_concat_max_len。

GROUP_CONCAT 去重:必须用 DISTINCT
MySQL 的 GROUP_CONCAT 本身不自动去重,拼接重复值是常见问题。想在聚合前就剔除重复项,得显式加 DISTINCT 关键字——它作用于分组内的行集合,不是对结果字符串做后处理。
比如查每个部门的员工技能,但同一人可能有多个相同技能记录:
SELECT dept, GROUP_CONCAT(DISTINCT skill ORDER BY skill) AS skills FROM employees GROUP BY dept;
漏掉 DISTINCT 就会得到 "Java,Python,Java,SQL" 这类含重复项的字符串;加上后才是 "Java,Python,SQL"。
-
DISTINCT必须紧贴在GROUP_CONCAT括号内第一个字段前,不能写成GROUP_CONCAT(skill DISTINCT) - 若字段组合重复(如
(skill, level)),DISTINCT对整行生效,不是单字段 - SQLite 和 PostgreSQL 没有原生
GROUP_CONCAT,得用string_agg(DISTINCT ...)(PG 14+)或子查询绕过
ORDER BY 在 GROUP_CONCAT 内部才生效
GROUP_CONCAT 的排序必须写在函数内部,用 ORDER BY 子句。写在外层 SELECT 或 GROUP BY 后面完全无效——因为分组后只剩单个字符串,外层排序只是排这些字符串本身,不是排串内元素。
正确写法:
SELECT user_id, GROUP_CONCAT(tag ORDER BY tag DESC SEPARATOR ';') FROM user_tags GROUP BY user_id;
错误写法(无意义):
-- 这里 ORDER BY 不影响拼接内容 SELECT user_id, GROUP_CONCAT(tag) FROM user_tags GROUP BY user_id ORDER BY tag; -- ❌ tag 已不在 SELECT 列表中,报错或逻辑错
-
ORDER BY支持多字段、ASC/DESC、表达式,如ORDER BY LENGTH(tag) DESC, tag -
SEPARATOR默认是逗号,设为空字符串''可实现无缝拼接,但要注意和去重逻辑配合 - 排序发生在去重之后,所以
DISTINCT+ORDER BY是安全组合
超长截断风险:SET group_concat_max_len 要提前调
MySQL 默认 group_concat_max_len = 1024,拼接结果超长会被静默截断,且不报错。线上查出的“技能列表突然变短”,八成是这个坑。
临时生效(当前 session):
SET SESSION group_concat_max_len = 1000000;
永久生效需改配置文件 my.cnf:
[mysqld] group_concat_max_len = 1000000
- 该变量只影响
GROUP_CONCAT,不影响其他聚合函数 - 数值单位是字节,不是字符数,UTF-8 下中文占 3 字节,要留足余量
- 若用视图或存储过程封装了拼接逻辑,必须在调用前 SET,否则继承连接默认值
PostgreSQL / SQLite 用户别硬套 GROUP_CONCAT
PostgreSQL 用 string_agg,语法更严格:去重必须靠子查询或 DISTINCT ON,且 ORDER BY 是独立参数,不是嵌在函数里。
-- PG 正确写法(14+ 支持 DISTINCT) SELECT dept, string_agg(DISTINCT skill, ',' ORDER BY skill) FROM employees GROUP BY dept; <p>-- 旧版 PG 或需要复杂去重时,用子查询 SELECT dept, string_agg(skill, ',') FROM (SELECT DISTINCT dept, skill FROM employees) t GROUP BY dept;
SQLite 的 GROUP_CONCAT 不支持 DISTINCT 和内置 ORDER BY,只能靠外部排序或提前去重:
-- SQLite:先去重再拼接(依赖子查询支持) SELECT dept, GROUP_CONCAT(skill, ',') FROM (SELECT DISTINCT dept, skill FROM employees ORDER BY dept, skill) GROUP BY dept;
跨数据库写法不可兼得,得按引擎特性拆逻辑。
真正容易被忽略的是:去重和排序的执行顺序依赖具体函数实现,不是 SQL 标准行为。MySQL 的 DISTINCT + ORDER BY 是原子操作,但有些旧版本或兼容模式下,ORDER BY 可能作用于去重前的原始集——务必在目标环境实测输出结果。

















