YashanDB LISTAGG函数

LISTAGG函数将多行的expr执行拼接操作,并通过分隔符分隔,返回一行VARCHAR/RAW类型的字符串。

expr不能为BIT、BOOLEAN、NCHAR、NVARCHAR、NCLOB和UDT类型。

当expr的类型为RAW时,函数返回RAW类型,否则函数返回VARCHAR类型。

DISTINCT

计算最终拼接结果时,过滤在同一组内出现的重复的行。

ALL

默认值,表示不过滤重复的行,对所有行都进行拼接。

separator

用于定义分隔符。不指定separator时,默认分隔符为NULL。

separator可以为常量(含常量表达式)或绑定参数的变量表达式,其数据类型不能为BOOLEAN、BIT、CLOB、BLOB、JSON、UDT、XMLTYPE和NCLOB。

当expr为RAW类型时,separator必须为RAW(或可以隐式转换为RAW)类型。

当expr为NULL时,该行数据会被忽略。

listagg_overflow_clause

listagg_overflow_clause

on overflow error on overflow truncate ' text ' with without count

当终止符或分隔符长度超过8000或者(分隔符长度)+ (终止符长度)+ (withcount26个字节)超过8000, 直接报错。

当拼接的结果发生溢出时候(即拼接的expr+分隔符>8000时)进行特殊处理:

  • on overflow error:默认选项,发生溢出时直接报错。
  • on overflow truncate(text):text是指定的终止标志(即终止符),在发生溢出后需要预留位置用来放置终止标志,默认终止标志为'...'占3个字节。
    • with count:发生溢出时且使用truncate时,默认输出count。在发生溢出后需要预留26个字节(给count预留24个字符,括号预留2个字符)。将已经拼接的行数往回回滚到可以放置需要给"(count)"和终止标志预留的字节数,将最终溢出的行数赋值给count。使用方法例如on overflow truncate '*' with count。
    • without count:在截断后面不显示截断的行数,发生溢出时需要为终止标志预留位置,不需要为"(count)"预留位置。例如on overflow truncate '*' without count。

指定终止符退化成默认的终止符的情况:

  • 如果是without count,当终止符或分隔符长度超过4000或者终止符+分隔符长度超过4000,终止符退化成'...'显示,并且不显示分隔符;如果前面条件不成立,那么会显示可以显示的行数+分隔符+终止符(可显示的行数可能为0)
  • 如果是with count或者缺省时,当终止符或分隔符长度超过4000-2-24 = 3974或者终止符+分隔符长度超过3974, 显示count,终止符退化成'...'显示,并且不显示分隔符;如果前面条件不成立,那么会显示可以显示的行数+分隔符+终止符+count(可显示的行数可能为0)

within group order_by_clause

对组内需要拼接的数据进行排序后再拼接。

作为非窗口函数时,本关键字仅适用于HEAP表。

示例(HEAP表)


DROP TABLE IF EXISTS exprs;
CREATE TABLE exprs(id INT , name VARCHAR(8000) , class RAW(300));
INSERT INTO exprs VALUES(1,'carrot','012');
INSERT INTO exprs VALUES(3,'rabbit','0ea');
INSERT INTO exprs VALUES(3,'carrot','66734');
INSERT INTO exprs VALUES(2,'clion','012');
INSERT INTO exprs VALUES(3,'apple','12900');
COMMIT;


SELECT LISTAGG(name) res FROM exprs;
RES

carrotrabbitcarrotclionapple                                    

SELECT LISTAGG(class,'00a') res FROM exprs;
RES

0012000A00EA000A066734000A0012000A012900          


SELECT LISTAGG(DISTINCT name ,' ;') res FROM exprs;
RES

apple ;carrot ;clion ;rabbit
    

SELECT LISTAGG(name,';') within GROUP(ORDER BY name) FROM exprs;
NAME

apple;carrot;carrot;clion;rabbit


SELECT id,LISTAGG(name,' ') within GROUP(ORDER BY name) FROM exprs GROUP BY id;
          ID NAME

           1 carrot
           3 apple carrot rabbit
           2 clion


DELETE exprs;
INSERT INTO exprs(name) VALUES(LPAD('as',4000,'cad'));
INSERT INTO exprs(name) VALUES(LPAD('dj',3000,'cad'));
INSERT INTO exprs(name) VALUES(LPAD('sd',500,'cdua'));
INSERT INTO exprs(name) VALUES(LPAD('sss',200,'cpd'));
INSERT INTO exprs(name) VALUES(LPAD('asiufs',100,'cod'));
INSERT INTO exprs(name) VALUES(LPAD('affs',300,'cdd'));


SELECT LISTAGG(name,';' ON overflow error) FROM exprs;
YAS-02511 result of string concatenation value exceeds maximum length of 8000 characters


SELECT LISTAGG(name,';' ON overflow TRUNCATE) res FROM exprs;

......ss;codcodcodcodcodcodcodcodcodcodcodcodcodcodcodcodcodcodcodcodcodcodcodcodcodcodcodcodcodcodcodcasiufs;...(1)

示例(TAC表、LSC表)


DROP TABLE IF EXISTS exprs;
CREATE TABLE exprs(id INT , name VARCHAR(8000) , class RAW(300));
INSERT INTO exprs VALUES(1,'carrot','012');
INSERT INTO exprs VALUES(3,'rabbit','0ea');
INSERT INTO exprs VALUES(3,'carrot','66734');
INSERT INTO exprs VALUES(2,'clion','012');
INSERT INTO exprs VALUES(3,'apple','12900');
COMMIT;


SELECT LISTAGG(name) res FROM exprs;
RES

carrotrabbitcarrotclionapple                                    

SELECT LISTAGG(class,'00a') res FROM exprs;
RES

0012000A00EA000A066734000A0012000A012900          


SELECT LISTAGG(DISTINCT name ,' ;') res FROM exprs;
RES

apple ;carrot ;clion ;rabbit


DELETE exprs;
INSERT INTO exprs(name) VALUES(LPAD('as',4000,'cad'));
INSERT INTO exprs(name) VALUES(LPAD('dj',3000,'cad'));
INSERT INTO exprs(name) VALUES(LPAD('sd',500,'cdua'));
INSERT INTO exprs(name) VALUES(LPAD('sss',200,'cpd'));
INSERT INTO exprs(name) VALUES(LPAD('asiufs',100,'cod'));
INSERT INTO exprs(name) VALUES(LPAD('affs',300,'cdd'));


SELECT LISTAGG(name,';' ON overflow error) FROM exprs;
YAS-05005 result of string concatenation value exceeds maximum length of 8000 characters


SELECT LISTAGG(name,';' ON overflow TRUNCATE) res FROM exprs;

......ss;codcodcodcodcodcodcodcodcodcodcodcodcodcodcodcodcodcodcodcodcodcodcodcodcodcodcodcodcodcodcodcasiufs;...(1)

OVER

当指定OVER关键字时,LISTAGG将作为窗口函数,将每个分组窗口内的行进行拼接,分组窗口内每一行的拼接结果都相同。

query_partition_clause

窗口函数通用语法。

示例


DROP TABLE IF EXISTS exprs;
CREATE TABLE exprs(id INT , name VARCHAR(8000) , class RAW(300));
INSERT INTO exprs VALUES(1,'carrot','012');
INSERT INTO exprs VALUES(3,'rabbit','0ea');
INSERT INTO exprs VALUES(3,'carrot','66734');
INSERT INTO exprs VALUES(2,'clion','012');
INSERT INTO exprs VALUES(3,'apple','12900');
COMMIT;


SELECT id,name,
LISTAGG(name, ',') OVER (PARTITION BY id) c1,
MAX(name) OVER (PARTITION BY id ORDER BY name) c2
FROM exprs;
 ID NAME       C1                     C2        

  1 carrot     carrot                 carrot   
  2 clion      clion                  clion    
  3 apple      rabbit,carrot,apple    apple    
  3 carrot     rabbit,carrot,apple    carrot   
  3 rabbit     rabbit,carrot,apple    rabbit  
<think>好的,用户想了解Oracle中LISTAGG函数的用法及相关问题解决。首先,我需要回顾LISTAGG的基本功能和语法。这个函数用于将多行数据合并成一行,常用于字符串聚合。根据引用资料,它从11gR2版本引入,之后在12c和19c中增强了功能,比如错误处理和去重。 用户可能需要知道基本语法,比如使用WITHIN GROUP和ORDER BY来排序聚合结果。示例会帮助理解,比如部门员工姓名的合并。引用5提到必须分组,所以GROUP BY是必须的,但引用2也提到高级用法可以不用GROUP BY,这里需要确认正确用法,可能涉及到窗口函数的使用。 接下来是常见问题,比如重复值和去重。19c支持DISTINCT关键字,这在引用1提到,所以应该给出示例说明如何使用DISTINCT去重。还有NULL值的处理,引用4指出默认忽略NULL,但可以用NULLIF转换,这也要举例说明。 然后是报错处理,比如字符串连接过长的问题。引用3和引用5可能提到溢出错误,解决方案包括使用ON OVERFLOW子句,或者子字符串截取。需要说明不同版本的解决方法,比如12c的ON OVERFLOW TRUNCATE,以及旧版本的SUBSTR方法。 还要注意用户可能遇到的GROUP BY问题,如引用2中Navicat使用时的限制,可能需要调整查询结构,确保GROUP BY包含所有非聚合列。或者使用窗口函数避免GROUP BY,但需要正确使用OVER PARTITION BY。 最后,总结版本差异和最佳实践,帮助用户根据实际情况选择合适的解决方案。检查是否有遗漏点,比如性能问题或应用场景,但根据用户提问,重点在用法、示例、报错处理,所以需紧扣这些方面组织信息。</think>### Oracle LISTAGG函数详解 #### 一、基础用法 LISTAGG用于将多行数据合并为单行字符串,语法结构为: $$LISTAGG(measure_column, delimiter) WITHIN GROUP (order_by_clause)$$ * **measure_column**:需要聚合的列 * **delimiter**:分隔符(可省略) * **order_by_clause**:排序规则(必填) **示例1**:按部门合并员工姓名 ```sql SELECT department, LISTAGG(name, ', ') WITHIN GROUP (ORDER BY name) AS employees FROM employees GROUP BY department; ``` 输出示例:`研发部 -> 张三, 李四, 王五`[^5] #### 二、进阶特性 1. **DISTINCT去重**(19c+) ```sql SELECT department, LISTAGG(DISTINCT name, ', ') WITHIN GROUP (ORDER BY name) FROM employees GROUP BY department; ``` 可消除重复姓名[^1] 2. **NULL值处理** ```sql SELECT department, LISTAGG(NVL(name, '无名氏'), ', ') WITHIN GROUP (ORDER BY name) FROM employees GROUP BY department; ``` 将NULL转换为指定值[^4] #### 三、常见报错及解决方案 1. **ORA-01489: 字符串连接的结果过长** * **12c+解决方案**: ```sql LISTAGG(name, ', ') ON OVERFLOW TRUNCATE '...' WITH COUNT ``` 自动截断超长字符串[^3] * **通用方案**: ```sql SUBSTR(LISTAGG(name, ', ') WITHIN GROUP (ORDER BY name), 1, 4000) ``` 手动限制字符串长度 2. **GROUP BY约束问题** 错误场景: ```sql SELECT department, name, -- name未在GROUP BY中 LISTAGG(skill, ', ') FROM employees; ``` 正确写法: ```sql SELECT department, name, LISTAGG(skill, ', ') WITHIN GROUP (ORDER BY skill) OVER (PARTITION BY department, name) FROM employees; ``` 使用窗口函数避免GROUP BY[^2] #### 四、版本差异对照表 | 版本 | 新功能 | |------|--------| | 11gR2 | 基础功能 | | 12c | 溢出处理 | | 19c | DISTINCT去重 | #### 五、最佳实践建议 1. 处理超长文本时优先使用`ON OVERFLOW`子句 2. 包含非分组字段时使用窗口函数 3. 需要跨版本兼容时,采用`SUBSTR+LISTAGG`组合
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值