使用 wm_concat() 得到 ORA-22922(不存在的 LOB 值)或根本没有结果
Getting ORA-22922 (nonexistent LOB value) or no result at all with wm_concat()
(使用 Oracle 11.2)
我有一个相当复杂的 SQL,比如
wm_concat( distinct abc )
预计 return 一些 varchar2(4000)
兼容结果。
它导致 ORA-00932: inconsistent datatypes
在我的 select 中用于某些 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) no result 或 O) ORA-22922
:
select * from view_with_above_included where rownum <= 100
N) 我的Eclipse Data Explorer JDBC连接returns没有任何结果(没有没有结果的列,没有(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 个字符的聚合数据。
幸运的是,它可以与自 11.2
以来提供的 listagg( ... )
功能一起使用(我们已经 运行 on),所以我们没有必须进一步调查:
listagg( abc, ',' ) within group ( order by abc )
(如您所知,wm_concat(...)
是一些官方不支持的内部函数。)
a rather nice solution(因为它不那么臃肿)实现distinct
功能是通过自引用正则表达式功能 在许多情况下应该有效:
regexp_replace(
listagg( abc, ',' ) within group ( order by abc )
, '(^|,)(.+)(,)+', '' )
(Maybe/Hopefully 我们将在未来看到一些可用的 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,
'([^,]+)(,)*(,|$)' AS list_dist_match, -- regexp match for distinct functionality
'' 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
(使用 Oracle 11.2)
我有一个相当复杂的 SQL,比如
wm_concat( distinct abc )
预计 return 一些 varchar2(4000)
兼容结果。
它导致 ORA-00932: inconsistent datatypes
在我的 select 中用于某些 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) no result 或 O) ORA-22922
:
select * from view_with_above_included where rownum <= 100
N) 我的Eclipse Data Explorer JDBC连接returns没有任何结果(没有没有结果的列,没有
(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 个字符的聚合数据。
幸运的是,它可以与自 11.2
以来提供的 listagg( ... )
功能一起使用(我们已经 运行 on),所以我们没有必须进一步调查:
listagg( abc, ',' ) within group ( order by abc )
(如您所知,wm_concat(...)
是一些官方不支持的内部函数。)
a rather nice solution(因为它不那么臃肿)实现distinct
功能是通过自引用正则表达式功能 在许多情况下应该有效:
regexp_replace(
listagg( abc, ',' ) within group ( order by abc )
, '(^|,)(.+)(,)+', '' )
(Maybe/Hopefully 我们将在未来看到一些可用的 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,
'([^,]+)(,)*(,|$)' AS list_dist_match, -- regexp match for distinct functionality
'' 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