listagg是oracle 11.2起官方支持的多行转一列函数,必须配合within group(order by ...)使用,支持分隔符、on overflow截断处理、null跳过及nvl转换,但不支持内置distinct且默认长度限4000字节。

LISTAGG 是 Oracle 11g R2 起官方支持的、最可靠且可预测的多行转一列方案。只要数据库版本 ≥ 11.2,就应优先用它,而不是 WM_CONCAT 或 XML 技巧。
LISTAGG 基础写法与必填项
LISTAGG 不是普通函数,它必须配合 WITHIN GROUP (ORDER BY ...) 使用,否则报错 ORA-30497: Missing keyword WITHIN。
这个子句不是可选的——哪怕你不需要排序,也得显式写上,比如 ORDER BY 1(按第一列升序)或 ORDER BY NULL(Oracle 允许,但语义模糊,不推荐)。
-
measure_column:要拼接的字段,支持表达式,如TO_CHAR(date_col, 'YYYY-MM') - 分隔符参数是可选的,但省略会导致所有值粘连,例如
LISTAGG(name)可能输出AliceBobCharlie - 必须有
GROUP BY,否则报ORA-00937: not a single-group group function
正确示例:
SELECT dept_id,
LISTAGG(emp_name, ', ') WITHIN GROUP (ORDER BY emp_name)
FROM employees
GROUP BY dept_id;
处理超长结果:ON OVERFLOW 截断或报错
LISTAGG 默认最大长度为 4000 字节(VARCHAR2 限制),超出会直接报错 ORA-01489: result of string concatenation is too long。
从 Oracle 12c 开始,可用 ON OVERFLOW 子句控制行为:
-
ON OVERFLOW TRUNCATE '...':截断并追加指定字符串,如'...',注意需预留空间 -
ON OVERFLOW ERROR:显式抛错(默认行为) -
ON OVERFLOW TRUNCATE(无替换字符串):截断但不提示,容易漏数据,慎用 -
ON OVERFLOW NULL:整个结果返回NULL,适合强校验场景
带截断的写法:
LISTAGG(emp_name, ', ') WITHIN GROUP (ORDER BY emp_name) ON OVERFLOW TRUNCATE '…' WITH COUNT
空值(NULL)和去重问题
LISTAGG 默认**跳过 NULL 值**,不会在结果中留空位或分隔符。这通常符合预期,但要注意:
- 如果整组都是
NULL,结果为NULL(不是空字符串) - 想把
NULL显示为特定字符串(如'(unknown)'),需提前用NVL或CASE转换 -
LISTAGG本身不支持DISTINCT,要去重必须在外层套SELECT DISTINCT或用子查询预处理
处理 NULL 的常见写法:
LISTAGG(NVL(emp_name, '(missing)'), ', ') WITHIN GROUP (ORDER BY emp_name)
性能与替代方案边界
LISTAGG 在多数场景下比自定义聚合或 XMLAGG 更快、更省内存,但有两个硬限制容易被忽略:
- 它只能用于聚合模式(
GROUP BY),不能直接作为分析函数(除非加OVER,但 12c+ 才支持,且仍受限于 4000 字节) - 当分组内行数极多(如 >5 万)、且单条结果逼近 32KB 时,内存压力会上升,可能触发临时表空间写入
此时可考虑降级方案:
- 仍用LISTAGG,但加 ROWNUM 限制拼接条数(业务可接受时)
- 改用 <code>XMLAGG(XMLELEMENT(...)).EXTRACT(...)(兼容 10g,支持 CLOB,但语法冗长、性能略低)
- 应用层分页聚合(如 Java Stream.collect + joining),把拼接逻辑移出 SQL
真正麻烦的不是语法写不对,而是忘了 ON OVERFLOW 和 NULL 处理——线上报表突然空白或截断,往往就卡在这两处。











