LISTAGG必须指定measure列和delimiter分隔符,并带WITHIN GROUP(ORDER BY...)子句;默认长度限4000字节,超长需ON OVERFLOW或XMLAGG;不支持DISTINCT,须预处理;NULL值自动跳过,但NULL分隔符导致结果为NULL。

LISTAGG 基本用法和必须指定的参数
Oracle 的 LISTAGG 不是“用了就能拼”,它强制要求两个核心参数:measure(要聚合的列)和 delimiter(分隔符)。漏掉任意一个会直接报错 ORA-00937: not a single-group group function,尤其新手常误以为只写列名就行。
正确写法必须带 WITHIN GROUP (ORDER BY ...) 子句,否则语法不完整:
SELECT LISTAGG(employee_name, ', ') WITHIN GROUP (ORDER BY hire_date) AS names FROM employees WHERE dept_id = 10;
-
employee_name是 measure,不能是表达式(如UPPER(name))除非用子查询或 CTE 包裹 - 分隔符
', '可以是空字符串'',但不能省略 -
ORDER BY必须在WITHIN GROUP内,不能写在外面的ORDER BY
处理超长结果:避免 ORA-01489 错误
LISTAGG 默认上限是 4000 字节(VARCHAR2 最大长度),聚合结果一旦超过就抛 ORA-01489: result of string concatenation is too long。这不是数据问题,是 Oracle 硬限制。
- Oracle 12cR2+ 支持
ON OVERFLOW TRUNCATE,但需显式声明返回类型为CLOB:
SELECT LISTAGG(employee_name, ', ')
WITHIN GROUP (ORDER BY hire_date)
ON OVERFLOW TRUNCATE '...' WITH COUNT
AS names
FROM employees;
- 更稳妥的做法是改用
XMLAGG+XMLELEMENT绕过长度限制(兼容 11g) - 注意:
ON OVERFLOW在 12cR1 及之前版本不可用,查V$VERSION确认版本
去重聚合:LISTAGG 本身不支持 DISTINCT
LISTAGG 的 measure 表达式里不能加 DISTINCT,写成 LISTAGG(DISTINCT name, ', ') 会语法报错。
- 必须提前去重:用子查询或
ROW_NUMBER()过滤重复项 - 常见写法是先
SELECT DISTINCT再套一层LISTAGG:
SELECT LISTAGG(name, ', ') WITHIN GROUP (ORDER BY name) AS deduped FROM (SELECT DISTINCT employee_name AS name FROM employees WHERE dept_id = 20);
- 如果要去重还要保序(比如按首次出现顺序),得用
ROW_NUMBER() OVER (PARTITION BY name ORDER BY hire_date)筛出每组第一条 - 别指望
GROUP BY外层加DISTINCT——LISTAGG是聚合函数,DISTINCT在其作用域外无效
空值和 NULL 分隔符的实际表现
LISTAGG 对 NULL 值默认静默跳过,不会插入空字符串或额外分隔符,这点和多数人直觉一致。但分隔符本身若为 NULL,结果会变成 NULL,不是无分隔拼接。
- 测试验证:
LISTAGG(name, NULL) WITHIN GROUP (ORDER BY id)永远返回NULL,哪怕所有name都非空 - 想跳过空值再聚合?不需要额外处理,
LISTAGG自动忽略NULL的measure值 - 但若需要把
NULL显式转成字符串(如'(missing)'),得用COALESCE(name, '(missing)')包一层
真正容易被忽略的是排序字段含 NULL 时的顺序 —— ORDER BY 中 NULLS FIRST/LAST 必须显式声明,否则 Oracle 版本间行为不一致(12c+ 默认 NULLS LAST,老版本可能相反)。


















