1

(使用 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),只有查询时间统计信息)。(这可能是一个内部异常,没有被这样对待?)

  • ○)

    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 个字符的聚合数据。

4

1 回答 1

5

幸运的是,它与提供的listagg( ... )函数一起工作11.2(我们已经在运行),所以我们不必进一步调查:

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

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


实现该功能的一个相当不错的解决方案(因为它不是那么臃肿)是通过自引用正则表达式功能,它应该在许多情况下工作:distinct

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

(也许/希望我们将来会看到一些工作listagg( distinct abc )功能,就像语法一样非常简洁和酷。例如,这在 Postgres' 1wm_concat很长时间以来都没有问题)string_agg( distinct abc )

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

如果列表超过 4000 个字符则不listagg能再使用(ORA-22922再次)。但幸运的是,我们可以在此处使用该功能xmlagg(如此处所述)。如果您想在此处实现4000-chars-truncated 的结果,您可以将-marked lines注释掉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
于 2016-09-05T07:38:28.353 回答