必须用listagg替代wm_concat,因后者是非官方私有函数,从12c起默认不可见、19c/21c中彻底移除,且存在截断、无排序、硬编码逗号等严重缺陷;listagg是标准函数,支持显式排序、自定义分隔符及超长处理。

Oracle 11g R2 及以后版本必须用 LISTAGG,WM_CONCAT 是非官方、不支持、随时可能失效的私有函数,生产环境禁用。
为什么不能用 WM_CONCAT?
WM_CONCAT 是 Oracle Workspace Manager 组件里的内部函数,未在文档中公开,从 12c 开始默认不可见,19c/21c 中已彻底移除或抛出 ORA-00904: "WM_CONCAT": invalid identifier 错误。即使在 11g 中能用,也存在严重缺陷:
- 返回类型固定为
CLOB或VARCHAR2(4000),超长直接截断无提示 - 不支持排序,拼接顺序依赖执行计划,不可控
- 无法指定分隔符,硬编码为逗号,且不能替换
- 跨数据库迁移或升级时大概率崩溃
LISTAGG 的基本用法与排序关键
LISTAGG 是标准聚合函数,语法清晰、行为稳定,但必须显式声明 WITHIN GROUP (ORDER BY ...),否则报错 ORA-30497: Argument should be a constant or a function of expressions in GROUP BY。
正确写法示例(按姓名升序拼接):
SELECT LISTAGG(name, ', ') WITHIN GROUP (ORDER BY name) AS names FROM employees WHERE dept_id = 10;
-
name是要拼接的列,', '是分隔符(可为任意字符串,包括空串'') -
ORDER BY必须存在,可多列、可加DESC,如ORDER BY salary DESC, name ASC - 若需去重,必须提前用子查询或 CTE 过滤,
LISTAGG本身不支持DISTINCT
处理超长字符串:避免 ORA-01489
当拼接结果超过 4000 字节(VARCHAR2 上限),会触发 ORA-01489: result of string concatenation is too long。解决方式只有两种:
- 强制转为
CLOB:在 12cR2+ 中,将分隔符设为CLOB类型即可,例如LISTAGG(name, TO_CLOB(', ')) WITHIN GROUP (...) - 截断并标记:用
ON OVERFLOW TRUNCATE '...'(12cR2+ 支持),如LISTAGG(name, ', ') WITHIN GROUP (...) ON OVERFLOW TRUNCATE '...' WITHOUT COUNT - 注意:
ON OVERFLOW在 11g 和 12cR1 中不可用,只能靠应用层预估长度或分批聚合
兼容旧版本或复杂逻辑的替代方案
如果卡在 11g R1 或必须支持极老环境,且不能用 WM_CONCAT,可用以下安全替代:
- 自定义聚合函数(需 CREATE TYPE 权限):定义
STRING_AGG_TYPE+ODCIAggregate*接口,可控性强但开发成本高 - 递归
WITH(11gR2+):适合行数不多、需条件拼接的场景,例如只拼接状态为 'A' 的记录,并带序号 - 应用层拼接:把结果集查出后由 Java/Python 等处理,避免数据库端复杂逻辑,尤其适合拼接内容需格式化或含逻辑分支时
真正容易被忽略的是:即使用了 LISTAGG,如果 ORDER BY 列存在 NULL,默认排在最前(NULLS FIRST),而多数业务希望 NULL 排末尾——这时必须显式写 ORDER BY col NULLS LAST,否则拼接结果顺序会意外错乱。











