listagg基本用法是分组后字符串拼接,必须配合group by使用,语法为listagg(expr, delimiter) within group (order by sort_expr),三者缺一不可;默认忽略null值但不自动去重,超长时需显式声明on overflow truncate避免ora-01489错误。

LISTAGG 基本用法:分组后字符串拼接
LISTAGG 是 Oracle 11gR2 引入的聚合函数,专用于将同一分组内的多行值拼成单个字符串。它必须配合 GROUP BY 使用,不能单独出现在无分组的查询中。
最简形式是:LISTAGG(expr, delimiter) WITHIN GROUP (ORDER BY sort_expr) —— 注意三个部分缺一不可:表达式、分隔符、显式 ORDER BY。
常见错误现象:ORA-00937: not a single-group group function,通常是因为漏了 GROUP BY;ORA-30496: Argument should be a constant 则多因 delimiter 写成了列名或子查询。
-
expr可以是列名(如employee_name)、表达式(如UPPER(dept)),但不能是聚合函数(如COUNT(*)) -
delimiter必须是常量字符串,比如','或'; ',不能是字段或NULL -
ORDER BY子句在WITHIN GROUP内部,且只接受列名或表达式,不支持位置编号(如ORDER BY 1)
处理超长结果:避免 ORA-01489 错误
默认情况下,LISTAGG 结果最大长度为 4000 字节(CHAR 模式下)或 32767 字节(启用 ON OVERFLOW TRUNCATE 前提下)。超出即报 ORA-01489: result of string concatenation is too long。
Oracle 12cR2 起支持溢出控制语法,但必须显式声明:
LISTAGG(employee_name, ', ') WITHIN GROUP (ORDER BY hire_date) ON OVERFLOW TRUNCATE '...' WITH COUNT
注意:ON OVERFLOW 后只能跟 TRUNCATE(不可省略),WITH COUNT 是可选的,会追加截断计数(如 ... (2 more));若省略则只显示省略号。
- 不加
ON OVERFLOW时,只要结果超限,整个查询直接报错,不会静默截断 -
TRUNCATE后的替换字符串长度计入总长,所以'...'实际占用 3 字节 - 如果目标字段定义为
CLOB,可考虑改用XMLAGG+XMLELEMENT绕过长度限制
空值与重复值的控制逻辑
LISTAGG 默认忽略 NULL 值,不会插入空项或额外分隔符 —— 这点和多数人直觉一致,无需额外处理。
但重复值不会自动去重。例如对 ['A', 'A', 'B'] 执行 LISTAGG(col, ','),结果是 'A,A,B',不是 'A,B'。
去重需前置处理,典型做法是用子查询套一层 DISTINCT:
SELECT dept_id,
LISTAGG(emp_name, ', ') WITHIN GROUP (ORDER BY emp_name)
FROM (
SELECT DISTINCT dept_id, emp_name
FROM employees
)
GROUP BY dept_id
- 不能在
LISTAGG内部写DISTINCT emp_name—— 语法不支持 - 若去重要求复杂(如按最新时间取唯一值),需用
ROW_NUMBER()窗口函数预过滤 - 当
expr本身含逗号等特殊字符,且下游要解析,建议提前用REPLACE或双引号包裹,而非依赖LISTAGG处理
替代方案对比:XMLAGG 与 MATCH_RECOGNIZE
当 LISTAGG 不可用(如老版本 Oracle)或需要更灵活控制时,XMLAGG 是最常用替代:
SELECT dept_id,
RTRIM(
EXTRACT(XMLAGG(XMLELEMENT("x", employee_name || ', ')), '/x/text()').getstringval(),
', '
) AS names
FROM employees
GROUP BY dept_id
它的优势是天然支持 CLOB,无 4000 字节硬限制;缺点是语法冗长、可读性差,且 EXTRACT 在某些字符集下可能抛异常。
Oracle 12c 起还可考虑 MATCH_RECOGNIZE,但它更适合带状态的序列分析,单纯拼接属于大材小用,维护成本高,一般不推荐。
真正容易被忽略的是排序稳定性:LISTAGG 的 ORDER BY 若未覆盖所有行的全序(比如多个员工 hire_date 相同),结果顺序可能每次执行不一致 —— 生产环境务必补上二级排序,如 ORDER BY hire_date, employee_id。











