2013-02-13 96 views
11

当我运行以下查询:LISTAGG功能和ORA-01489:字符串连接的结果是太长

Select 
    tm.product_id, 
    listagg(tm.book_id || '(' || tm.score || ')',',') 
    within group (order by tm.product_id) as matches 
from 
    tl_product_match tm 
where 
    tm.book_id is not null 
group by 
    tm.product_id 

Oracle返回以下错误:

ORA-01489: result of string concatenation is too long 

我知道原因,失败的原因是listagg函数试图连接大于4000个不支持的字符值。

我已经看到了这里描述的替代示例 - http://www.oracle-base.com/articles/misc/string-aggregation-techniques.php,但它们都需要使用函数或过程。

是否有一种解决方案是纯SQL,无需调用函数或存储过程,并且可以使用标准JDBC读取值?

我遇到的另一个困难是我看到的大多数字符串聚合示例都显示了如何按照原样读取值的示例。在我的示例中,我首先修改了值(即,我正在汇总两列)。

回答

0

I have seen the alternative example described here - http://www.oracle-base.com/articles/misc/string-aggregation-techniques.php but they all require the use of functions or procedure.

不,他们没有。向下滚动,你会看到几个不需要pl/sql的选项。

+2

对我来说,任何这些解决方案都不支持返回'CLOB'而不需要创建任何PL/SQL对象。您认为该页面上的哪个选项符合这两个标准? – 2013-02-13 22:21:20

6

你可以使用xml函数来做它,它返回一个CLOB。 JDBC应该没问题。

select tm.product_id, 
     rtrim(extract(xmlagg(xmlelement(e, tm.book_id || '(' || tm.score || '),')), 
       '/E/text()').getclobval(), ',') 
    from tl_product_match tm 
where tm.book_id is not null 
group by tm.product_id; 

如:http://sqlfiddle.com/#!4/083a2/1

+0

我试过XML版本,速度很慢。它通常比纯sql慢吗? – ziggy 2013-02-14 11:19:04

+0

使用listagg的原始查询需要0.872秒,而XML版本需要4.461秒 – ziggy 2013-02-14 11:25:57

+0

@ziggy它可能会慢一点,因为我们不得不涉及xml,并且这还会返回一个会产生一些开销的clob。我还假设你的计时在listagg没有崩溃的同一组中:) – DazzaL 2013-02-14 11:37:23

3

为什么不使用嵌套表?

set echo on; 
set display on; 
set linesize 200; 

drop table testA; 
create table testA 
(
col1 number, 
col2 varchar2(50) 
); 

drop table testB; 
create table testB 
(
col1 number, 
col2 varchar2(50) 
); 

create or replace type t_vchar_tab as table of varchar2(50); 

insert into testA values (1,'A'); 
insert into testA values (2,'B'); 

insert into testB values (1,'X'); 
insert into testB values (1,'Y'); 
insert into testB values (1,'Z'); 
commit; 

-- select all related testB.col2 values in a nested table for each testA.col1 value 
select a.col1, 
cast(multiset(select b.col2 from testB b where b.col1 = a.col1 order by b.col2) as t_vchar_tab) as testB_vals 
from testA a; 

-- test size > 4000 
insert into testB 
select 2 as col1, substr((object_name || object_type), 1, 50) as col2 
from all_objects; 
commit; 

-- select all related testB.col2 values in a nested table for each testA.col1 value 
select a.col1, 
cast(multiset(select b.col2 from testB b where b.col1 = a.col1 order by b.col2) as t_vchar_tab) as testB_vals 
from testA a; 

我不是Java专家,但是这已经有一段时间,我敢肯定,Java可以拉出来的值的嵌套表。而且,不需要在另一端标记一些分隔字符串。

+0

这是一个很棒的建议 – 2018-02-15 16:13:51