Oracle 19c 中 WM_CONCAT 已被彻底移除,必须改用 LISTAGG 或自定义聚合函数,否则报 ORA-00904 错误;LISTAGG 是首选方案,但需显式指定分隔符和 WITHIN GROUP 排序,且默认受限于 4000 字符长度。

Oracle 19c 中 WM_CONCAT 已被彻底移除,不能直接使用;必须改用 LISTAGG 或自定义聚合函数,否则会报 ORA-00904: invalid identifier 错误。
LISTAGG 是首选替代方案,但要注意分隔符和排序写法
它不是简单替换函数名,而是语法结构完全不同:LISTAGG 必须显式声明分隔符和排序逻辑,否则结果不可控。
- 错误写法:
SELECT LISTAGG(ename) FROM emp GROUP BY deptno→ 缺少WITHIN GROUP,报错 - 正确写法:
SELECT deptno, LISTAGG(ename, ',') WITHIN GROUP (ORDER BY ename) FROM emp GROUP BY deptno - 分隔符可以是任意字符串,比如
' | '或chr(10)(换行),但不能是空字符串(会报ORA-30496) - 排序字段不必是聚合字段本身,例如可按
empno排序:WITHIN GROUP (ORDER BY empno)
LISTAGG 的 4000 字符限制与溢出处理
LISTAGG 默认返回 VARCHAR2(4000),超长会直接报 ORA-01489: result of string concatenation is too long,不像 WM_CONCAT 那样自动转为 CLOB。
- Oracle 12cR2 起支持
ON OVERFLOW TRUNCATE选项,但默认不启用,需显式加:LISTAGG(ename, ',') WITHIN GROUP (...) ON OVERFLOW TRUNCATE '...' WITHOUT COUNT - 若必须返回完整内容,可用
XMLAGG+GETCLOBVAL()绕过长度限制,但性能明显下降(实测慢 3–5 倍) - 不要依赖
TO_CLOB(LISTAGG(...)),这无法解决溢出问题,只在结果未超长时才有效
自定义 WM_CONCAT_IMPL 类型仅适用于强兼容需求
重建 WM_CONCAT 不是“恢复功能”,而是模拟旧行为——它没有排序能力、固定逗号分隔、且返回类型受限于你定义的 VARCHAR2 长度(如 VARCHAR2(32767))。
- 创建前必须确认用户有
CREATE TYPE权限,且不能在WMSYS下操作(该用户在 19c 中默认锁定且不应解锁) - 类型体中拼接逻辑无空值过滤,
NULL字段会导致整个拼接中断或产生意外空格,需在调用前用NVL处理 - 并行查询下依赖
ODCIAggregateMerge实现合并,若未正确定义该方法,结果可能随机缺失部分数据 - 该方案无法解决旧代码中隐含的排序依赖(比如靠执行计划巧合实现的顺序),上线前必须做全量数据比对
别忽略 XMLAGG 这个冷门但稳定的备选
当 LISTAGG 因长度或排序复杂度受限,又不想维护自定义类型时,XMLAGG 是更轻量的兜底方案,尤其适合中间层视图或 ETL 场景。
- 基本写法:
XMLAGG(XMLELEMENT(E, ename || ',') ORDER BY ename).EXTRACT('//text()').GETCLOBVAL() - 结尾多出的逗号需用
RTRIM(..., ',')清理,否则和原WM_CONCAT行为不一致 - 性能比
LISTAGG差,但比自定义类型稳定,且天然支持CLOB输出,无 4000 字符硬限制 - 注意:YashanDB 等国产库不支持
XMLAGG,跨平台迁移时需提前识别
真正容易被忽略的是排序一致性——WM_CONCAT 从不保证顺序,而 LISTAGG 强制要求 WITHIN GROUP,一旦漏写或排序字段有重复值,结果就不可复现。生产环境上线前,务必用小批量数据验证输出顺序是否符合业务预期。











