【问题标题】:Listagg function and ORA-01489: result of string concatenation is too longListagg 函数和 ORA-01489:字符串连接的结果太长
【发布时间】:2013-01-29 14:51:28
【问题描述】:

当我运行以下查询时:

 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 读取值?

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

【问题讨论】:

    标签: java oracle jdbc oracle10g oracle11g


    【解决方案1】:

    您可以使用返回 CLOB 的 xml 函数来执行此操作。 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

    【讨论】:

    • 我试过XML版本,速度很慢。它通常比纯sql慢吗?
    • 使用 listagg 的原始查询需要 0.872 秒,而 XML 版本需要 4.461 秒
    • @ziggy 它可能会更慢,是的,因为我们必须涉及 xml,而且这会返回一个会产生一些开销的 clob。我还假设您的时间安排在 listagg 没有崩溃的同一组:​​)
    • 请注意xmlagg() 支持order by 子句:xmlagg(xmlelement(e, ...) order by tm.product_id)
    【解决方案2】:

    为什么不使用嵌套表?

    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 可以将值从嵌套表中提取出来。而且,不需要在另一端标记一些分隔字符串。

    【讨论】:

    • 这是一个很棒的建议
    【解决方案3】:

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

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

    【讨论】:

    • 对我来说,这些解决方案中的任何一个都支持返回 CLOB 并且不需要创建任何 PL/SQL 对象并不明显。您认为该页面上的哪个选项符合这两个标准?
    猜你喜欢
    • 2021-07-04
    • 2017-02-06
    • 2011-08-13
    • 2016-05-28
    • 2013-04-04
    • 1970-01-01
    • 2019-03-15
    • 2015-06-28
    • 2012-05-12
    相关资源
    最近更新 更多