我需要在分层查询中写入帮助以获取子节点的父路径。我正在尝试使用函数sys_connect_by_path
,但我无法这样做,因为具有父标题的函数的结果超出了column(4000 chars)
的最大字符限制。因此,我需要将自定义集合中的路径保存到clob
中,我发现很难找到它。
示例:
contentid - parentid
0 - null
1 - 0
2 - 1
3 - 2
4 - 2
5 - 6
6 - 3
7 - 6
预期结果:
contentid - Expected result set
0 - null
1 - 0
2 - 1,0
3 - 2,1,0
4 - 2,1,0
5 - 6,3,2,1,0
6 - 3,2,1,0
7 - 6,3,2,1,0
查询将子节点的父路径转换为列
SELECT CHILD_ID,
PATH
FROM (SELECT sys_connect_by_path(CHILD_TITLE, '|') PATH
, connect_by_root(PARENT_ID) ROOT_ID, CHILD_ID
FROM table
CONNECT BY PRIOR CHILD_ID = PARENT_ID
ORDER BY CHILD_ID)
WHERE ROOT_ID IS NULL;
我需要一个可以容纳超过4000个字符的clob / custom集合。
答案 0 :(得分:1)
只要您使用11gR2或更高版本,就可以使用recursive subquery factoring代替connect by
分层语法。
如果您的表名为t
,请执行以下操作:
CHILD_ID PARENT_ID CHILD_T
---------- ---------- -------
0 root
1 0 first
2 1 second
3 2 third
4 2 fourth
5 6 fifth
6 3 sixth
7 6 seventh
你可以这样做:
with r (child_id, child_title, id_path, title_path) as (
select child_id, child_title, to_clob(null), to_clob(null)
from t
where parent_id is null
union all
select t.child_id, t.child_title,
t.parent_id ||','|| r.id_path, r.child_title ||'|'|| r.title_path
from r
join t on t.parent_id = r.child_id
)
select child_id, id_path, title_path
from r
order by child_id;
CHILD_ID ID_PATH TITLE_PATH
---------- -------------------- ----------------------------------------
0
1 0, root|
2 1,0, first|root|
3 2,1,0, second|first|root|
4 2,1,0, second|first|root|
5 6,3,2,1,0, sixth|third|second|first|root|
6 3,2,1,0, third|second|first|root|
7 6,3,2,1,0, sixth|third|second|first|root|
锚成员将路径转换为CLOB;递归成员将每个标题附加到CLOB,这使它保持为该数据类型。
您可以剪掉尾随的逗号/栏,或稍微修改一下查询,以免它们出现:
with r (parent_id, child_id, child_title, id_path, title_path) as (
select parent_id, child_id, child_title, to_clob(null), to_clob(null)
from t
where parent_id is null
union all
select t.parent_id, t.child_id, t.child_title,
t.parent_id || case when r.parent_id is not null then ',' end || r.id_path,
r.child_title || case when r.parent_id is not null then '|' end || r.title_path
from r
join t on t.parent_id = r.child_id
)
select child_id, id_path, title_path
from r
order by child_id;
CHILD_ID ID_PATH TITLE_PATH
---------- -------------------- ----------------------------------------
0
1 0 root
2 1,0 first|root
3 2,1,0 second|first|root
4 2,1,0 second|first|root
5 6,3,2,1,0 sixth|third|second|first|root
6 3,2,1,0 third|second|first|root
7 6,3,2,1,0 sixth|third|second|first|root
您的示例值并未证明需要CLOB,但向虚拟表中添加更多数据会显示生成的值可能超过4k:
insert into t
select level + 7, level + 6, 'title'
from dual
connect by level <= 2000;
with r (...) -- as above
select max(length(id_path)), max(length(title_path))
from r;
MAX(LENGTH(ID_PATH)) MAX(LENGTH(TITLE_PATH))
-------------------- -----------------------
8920 12031
答案 1 :(得分:0)
SYS_CONNECT_BY_PATH
几乎是LISTAGG
的应用程序,如下所示:首先生成所需的行,包括CONNECT_BY_ROOT
和LEVEL
,然后汇总。如下所示,更明确地执行此操作,可以让您更准确地控制聚合中的内容,使用级别的顺序等等。(注意:我不认为这就是Oracle在内部执行的方式,因为LISTAGG
的添加时间比SYS_CONNECT_BY_PATH
晚得多,但逻辑上就是它的工作方式。)
所以问题无论是4,000个字符的限制。与LISTAGG
函数并排,我使用XMLAGG
显示不同的聚合 - 它没有4,000个字符限制。对于大输入数据,LISTAGG
行将不起作用,但XMLAGG
行将正常工作并将产生CLOB。祝你好运!
<强>查询强>:
with
t ( child_id, parent_id ) as (
select 0, null from dual union all
select 1, 0 from dual union all
select 2, 1 from dual union all
select 3, 2 from dual union all
select 4, 2 from dual union all
select 5, 6 from dual union all
select 6, 3 from dual union all
select 7, 6 from dual
)
select child_id,
listagg(parent_id, ',') within group (order by lvl) as gen_tree_1,
rtrim(xmlcast(xmlagg(xmlelement(e, parent_id||',') order by lvl) as clob), ',')
as gen_tree_2
from ( select connect_by_root child_id as child_id, parent_id, level as lvl
from t
connect by child_id = prior parent_id
)
group by child_id
order by child_id
;
<强>输出强>:
CHILD_ID GEN_TREE_1 GEN_TREE_2
---------- -------------------- --------------------
0
1 0 0
2 1,0 1,0
3 2,1,0 2,1,0
4 2,1,0 2,1,0
5 6,3,2,1,0 6,3,2,1,0
6 3,2,1,0 3,2,1,0
7 6,3,2,1,0 6,3,2,1,0
8 rows selected.