PostgreSQL和Oracle的STRING_AGG/LISTAGG均不支持直接DISTINCT,需先用子查询或CTE去重;MySQL 8.0+的GROUP_CONCAT支持DISTINCT;跨库推荐ARRAY_AGG+ARRAY_TO_STRING或应用层处理。
STRING_AGG 里不能直接写 DISTINCT
PostgreSQL 的
函数本身不支持
关键字,像
这种写法会报错:
。这不是你语法写错,是函数设计如此——它只接受表达式,不解析子句。
正确做法是把去重逻辑提前到聚合前:用子查询或 CTE 先
,再喂给
。
例如,想按部门合并员工姓名且去重:
LISTAGG 在 Oracle 中也不允许直接 DISTINCT
Oracle 的
同样不接受
作为参数。尝试
会触发
或类似解析错误。
必须用内层去重。注意 Oracle 12c 及以后支持
子句,但去重仍需前置:
如果源数据本身有重复(比如同一人多条记录),漏掉外层
就会导致结果里出现重复名字
必须写在
后面,不能放在子查询里
Oracle 11g 不支持
,得用
(不推荐)或自定义聚合函数
MySQL 8.0+ 用 GROUP_CONCAT + DISTINCT 最省事
MySQL 是少数原生支持
直接入参的:你可以放心写
。
但要注意几个实际坑点:
默认长度上限是 1024 字符,超长会被截断,需提前设
作用于整个表达式,不是单列——
是拼接后去重,不是分别对
和
去重
空值(
)默认被忽略,不会出现在结果中;如果要显式显示,得用
预处理
跨数据库统一写法:用 ARRAY + 转字符串兜底
如果项目要兼容多个数据库(比如测试用 PostgreSQL、上线用 Oracle),硬套各平台语法容易翻车。更稳的方式是绕开字符串聚合函数,先聚合成数组,再转字符串:
PostgreSQL 示例:
这个组合天然支持
,因为
允许它,而
只负责拼接。Oracle 没有原生数组聚合,但可以用
+ 自定义函数模拟,不过代价高;MySQL 则没有标准数组类型,这条路走不通。
真正需要跨库时,最现实的方案还是在应用层做去重和拼接——SQL 只负责查出明细,别强求一步到位。
STRING_AGGDISTINCTSTRING_AGG(DISTINCT col, ',')ERROR: syntax error at or near "DISTINCT"DISTINCTSTRING_AGGSELECT dept,
STRING_AGG(name, ', ' ORDER BY name)
FROM (SELECT DISTINCT dept, name FROM employees) AS deduped
GROUP BY dept;LISTAGGDISTINCTLISTAGG(DISTINCT col, ',')ORA-30496: Argument should be a constantORDER BYSELECT dept,
LISTAGG(name, ', ') WITHIN GROUP (ORDER BY name)
FROM (SELECT DISTINCT dept, name FROM employees)
GROUP BY dept;DISTINCTWITHIN GROUPLISTAGGWITHIN GROUPWM_CONCATDISTINCTGROUP_CONCAT(DISTINCT col ORDER BY col SEPARATOR ', ')GROUP_CONCATSET SESSION group_concat_max_len = 1000000;DISTINCTGROUP_CONCAT(DISTINCT a, b)abNULLIFNULL(a, 'N/A')SELECT dept,
ARRAY_TO_STRING(ARRAY_AGG(DISTINCT name ORDER BY name), ', ')
FROM employees
GROUP BY dept;DISTINCTARRAY_AGGARRAY_TO_STRINGCOLLECT