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个字符的汇总数据。
幸运的是,它可以使用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个字符,一个不能用listagg了(ORA-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)