LISTAGG是Oracle 11.2起官方支持的多行转一列函数,必须配合WITHIN GROUP(ORDER BY)使用,支持分隔符、ON OVERFLOW截断、NULL跳过及NVL转换,但不支持内置DISTINCT且默认长度限4000字节。

Oracle 11g 及以上用 LISTAGG 最直接
LISTAGG 是 Oracle 原生聚合函数,专为字符串拼接设计,性能好、语法清晰。它要求指定分隔符和排序依据(WITHIN GROUP (ORDER BY ...) 不可省略,否则报错 ORA-30497)。
常见写法:
SELECT LISTAGG(name, ',') WITHIN GROUP (ORDER BY id) AS names FROM employees WHERE dept_id = 10;
注意点:
- 如果拼接结果超 4000 字节(
VARCHAR2限制),会报ORA-01489;12cR2+ 可改用LISTAGG(... ON OVERFLOW TRUNCATE)控制截断行为 - 空值(
NULL)默认被忽略,无需额外WHERE name IS NOT NULL - 排序字段必须存在于
SELECT或GROUP BY中,否则报ORA-00979
Oracle 10g 或需要兼容老版本时用 WM_CONCAT(不推荐)
WM_CONCAT 是 Oracle 内部 undocumented 函数,10g/11g 存在但 12c+ 已移除,且返回类型为 CLOB,容易引发隐式转换问题。仅作临时过渡,不可用于新项目。
示例(仅限 11g 及以下):
SELECT WM_CONCAT(name) AS names FROM employees WHERE dept_id = 10;
风险提示:
- 无内置排序能力,结果顺序不确定
- 遇到中文或特殊字符可能乱码(依赖数据库字符集与客户端设置)
- 无法控制溢出行为,超长时直接报错或截断,无提示
处理重复值或需条件过滤时,先 GROUP BY 再 LISTAGG
如果目标字段有重复,或需按某维度聚合后再拼接(比如每个部门拼一个字符串),必须显式 GROUP BY,且 LISTAGG 的 ORDER BY 字段必须包含在 GROUP BY 列表中。
错误写法(ORDER BY name 但未 GROUP BY name):
SELECT dept_name, LISTAGG(emp_name, ',') WITHIN GROUP (ORDER BY name) FROM dept_emp GROUP BY dept_name;
正确写法:
SELECT dept_name,
LISTAGG(emp_name, ',') WITHIN GROUP (ORDER BY emp_name) AS emps
FROM dept_emp
GROUP BY dept_name;
若要去重,得提前用子查询或 DISTINCT 视图:
SELECT dept_name,
LISTAGG(emp_name, ',') WITHIN GROUP (ORDER BY emp_name)
FROM (SELECT DISTINCT dept_name, emp_name FROM dept_emp)
GROUP BY dept_name;
拼接结果含单引号、逗号等特殊字符怎么办?
LISTAGG 本身不转义,遇到字段含单引号(如 O'Connor)或逗号(如 Smith, John),拼接后会破坏结构。这不是函数缺陷,而是业务需求层面的问题。
解决方案取决于下游用途:
- 若用于 SQL IN 列表:改用绑定变量或临时表,别拼成字符串
- 若导出为 CSV:用双引号包裹字段,例如
'''' || emp_name || ''''模拟转义(注意 Oracle 单引号需写两次) - 若需 JSON 格式:优先用
JSON_ARRAYAGG(12cR2+),比手动拼接更安全
真正麻烦的是嵌套场景——比如拼接结果还要再参与子查询或动态 SQL,这时候字符串注入风险陡增,得评估是否真有必要拼接,还是该用集合类型(COLLECTION)或应用层处理。


















