我正在尝试从Oracle创建一个XML,它们之间有父子关系。
表格数据如下所示。一个child_ID
可以与一个或多个parent_ID
相关联。
在此处,101
与2个ID 100
和200
相关联。
child_ID Parent_ID
-------- ---------
100 1000
101 100
102 100
101 200
1010 101
1011 101
1020 102
1021 102
如果parent_id
的输入值为100
,则XML应采用以下格式。
<view_hierarchy chm="com.hierarchy">
<link>
<ID refno="100">
<contained_by>
<ID refno="1000"/>
</contained_by>
<contains>
<ID refno="101">
<contained_by>
<ID refno="200"/>
</contained_by>
<contains>
<ID refno="1010">
</ID>
<ID refno="1011">
</ID>
</contains>
</ID>
<ID refno="102">
<contains>
<ID refno="1020">
</ID>
<ID refno="1021">
</ID>
</contains>
</ID>
</contains>
</ID>
</link>
</view_hierarchy>
此处contained_by
指的是与元素相关联的所有父级,contains
指的是与该元素相关的所有子级。
输入parent_id
值可能不同,因此需要为XML生成计算contains
和contained_by
。
答案 0 :(得分:1)
注意:在下文中,t_hierarchy
是您的源表(因为您未在问题中为其命名)。
虽然也许可以通过分层SQL来实现这一点,但我相信纯SQL将是一个 PITA 来实现,并且一个常规的递归PLSQL函数就可以了。
首先,创建一个简单的架构级集合类型
create or replace type arr_integers as table of integer;
然后是一个函数
create or replace
function f_parent_child_xml
( i_parent_id in t_hierarchy.parent_id%type
, i_visited_nodes in arr_integers default null )
return xmltype
is
l_result xmltype;
l_contained_by_xml xmltype;
l_contained_by# integer;
l_contains_xml xmltype;
l_contains# integer;
l_new_visited_nodes arr_integers;
begin
if i_visited_nodes is null then
select
xmlelement("view_hierarchy",
xmlattributes('com.hierarchy' as "chm"),
xmlelement("link",
f_parent_child_xml(i_parent_id, arr_integers())
))
into l_result
from dual;
else
select parent_id
bulk collect into l_new_visited_nodes
from t_hierarchy
where i_parent_id in (child_id, parent_id)
union
select child_id
from t_hierarchy
where i_parent_id in (child_id, parent_id)
union
select column_value
from table(i_visited_nodes);
select
xmlagg(
f_parent_child_xml(H1.parent_id, l_new_visited_nodes)
) as xml$,
count(1) as rows#
into l_contained_by_xml, l_contained_by#
from t_hierarchy H1
where H1.child_id = i_parent_id
and not exists (
select 1
from table(i_visited_nodes) X
where X.column_value = H1.parent_id
)
;
select
xmlagg(
f_parent_child_xml(H2.child_id, l_new_visited_nodes)
) as xml$,
count(1) as rows#
into l_contains_xml, l_contains#
from t_hierarchy H2
where H2.parent_id = i_parent_id
and not exists (
select 1
from table(i_visited_nodes) X
where X.column_value = H2.child_id
);
select
xmlelement("ID",
xmlattributes(i_parent_id as "refno"),
case when l_contained_by# > 0 then xmlelement("contained_by", l_contained_by_xml) end,
case when l_contains# > 0 then xmlelement("contains", l_contains_xml) end
)
into l_result
from dual;
end if;
return l_result;
end;
运行,例如
select f_parent_child_xml(101)
from dual;
或
select f_parent_child_xml(101).getStringVal()
from dual;
产量(手动重新格式化后):
<view_hierarchy chm="com.hierarchy">
<link>
<ID refno="101">
<contained_by>
<ID refno="100">
<contained_by>
<ID refno="1000"></ID>
</contained_by>
<contains>
<ID refno="102">
<contains>
<ID refno="1021"></ID>
<ID refno="1020"></ID>
</contains>
</ID>
</contains>
</ID>
<ID refno="200"></ID>
</contained_by>
<contains>
<ID refno="1011"></ID>
<ID refno="1010"></ID>
</contains>
</ID>
</link>
</view_hierarchy>
享受!