使用wm_concat()获得ORA-22922(不存在的LOB值)或根本没有结果

And*_*ich 0 casting oracle11g wm-concat

(使用Oracle 11.2)

我有一个相当复杂的SQL,类似于

wm_concat( distinct abc )
Run Code Online (Sandbox Code Playgroud)

预期会返回一些varchar2(4000)兼容的结果

它导致ORA-00932: inconsistent datatypes在我的选择中使用了一些coalesce( some_varchar_col, wm_concat( ... ) )


因此,我尝试通过两种不同的方法进行转换:

dbms_lob.substr( ..., 4000 )  -- L) tried even with 3000 in case of "unicode byte blow-up"
cast( ... as varchar2(4000))  -- C) tried even with 3000 in case of "unicode byte blow-up"
Run Code Online (Sandbox Code Playgroud)

(在视图中使用,但是尝试使用它表明它与视图无关)

根据列和其他运算符,我要么得到N)没有结果,要么得到O)ORA-22922

select * from view_with_above_included where rownum <= 100
Run Code Online (Sandbox Code Playgroud)
  • N)我的Eclipse Data Explorer JDBC连接返回没有任何结果(没有结果的列,没有结果,没有(0 rows effected),只有查询时间统计信息)。(这可能是内部异常而不是这样处理吗?)

  • O)

    ORA-22922: nonexistent LOB value
    ORA-06512: in "SYS.DBMS_LOB", line 1092
    ORA-06512: in line 1
    
    Run Code Online (Sandbox Code Playgroud)

奇怪的是,以下测试查询有效:

ORA-22922: nonexistent LOB value
ORA-06512: in "SYS.DBMS_LOB", line 1092
ORA-06512: in line 1
Run Code Online (Sandbox Code Playgroud)

要么

-- rownum <= 100 would already cause the above problems
select * from view_with_above_included where rownum <= 10
Run Code Online (Sandbox Code Playgroud)

但是查看实际的汇总数据不会显示长度超过1000个字符的汇总数据。

And*_*ich 5

幸运的是,它可以使用listagg( ... )11.2(我们已经在运行)以来提供的功能,因此我们无需进一步研究:

listagg( abc, ',' ) within group ( order by abc )
Run Code Online (Sandbox Code Playgroud)

wm_concat(...)应该知道,内部和官方不支持的功能在哪里。)


实施此功能的一个不错的解决方案(因为它没有那么ated肿)是通过自引用regexp功能,该功能在许多情况下都可以使用:distinct

regexp_replace( 
  listagg( abc, ',' ) within group ( order by abc )
, '(^|,)(.+)(,\2)+', '\1\2' )
Run Code Online (Sandbox Code Playgroud)

(也许/我希望我们会看到一些工作listagg( distinct abc )的功能在未来,这将是非常整洁,冷却像wm_concat语法。例如,这是因为长时间用的Postgres没问题string_agg( distinct abc )1

-- 1: postgres sql example:
select string_agg( distinct x, ',' ) from unnest('{a,b,a}'::text[]) as x`
Run Code Online (Sandbox Code Playgroud)

如果列表超过4000个字符,一个不能用listaggORA-22922再次)。但幸运的是我们可以使用xmlagg此功能(如提到这里)。如果要此处实现distinct截断4000个字符的结果,可以(1)带有- 标志的line进行注释

-- in smallercase everything that could/should be special for your query
-- comment in (1) to realize a distinct on a 4000 chars truncated result
WITH cfg AS ( 
  SELECT 
    ','                  AS list_delim,
    '([^,]+)(,\1)*(,|$)' AS list_dist_match,  -- regexp match for distinct functionality
    '\1\3'               AS LIST_DIST_REPL  -- regexp replace for distinct functionality
  FROM DUAL
)
SELECT
  --REGEXP_REPLACE( DBMS_LOB.SUBSTR(             -- (1)
  RTRIM( XMLAGG( XMLELEMENT( E, mycol, listdelim ).EXTRACT('//text()') 
  ORDER BY mycol ).GetClobVal(), LIST_DELIM ) 
  --, 4000 ), LIST_DIST_MATCH, LIST_DIST_REPL )  -- (1)
  AS mylist
FROM mytab, CFG
Run Code Online (Sandbox Code Playgroud)