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

时间:2016-09-05 07:38:28

标签: oracle11g casting wm-concat

(使用Oracle 11.2)

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

wm_concat( distinct abc )

预计会返回一些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"

(在视图中使用,但玩弄它表明,它与视图无关)

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

select * from view_with_above_included where rownum <= 100
  • 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
    

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

-- rownum <= 100 would already cause the above problems
select * from view_with_above_included where rownum <= 10

select * from view_with_above_included

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

1 个答案:

答案 0 :(得分:4)

幸运的是,它适用于自listagg( ... ) 以来提供的11.2功能(我们已经在运行),因此我们无需进一步调查:

listagg( abc, ',' ) within group ( order by abc )

(正如人们应该知道的那样,wm_concat(...)是一些内部和官方不支持的功能。)

rather nice solution (因为它不是那么臃肿)实现distinct功能是通过自引用正则表达式功能来实现的在很多情况下:

regexp_replace( 
  listagg( abc, ',' ) within group ( order by abc )
, '(^|,)(.+)(,\2)+', '\1\2' )

(也许/希望我们将来会看到一些有效的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`

如果列表超过4000个字符,则一个不能再使用listagg ORA-22922再次)。 但幸运的是,我们可以在这里使用xmlagg函数(如上所述here)。 如果您想在此处在4000字符截断的结果上实现distinct,则可以取消(1) - 标记的行

-- 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