层次记录

时间:2014-12-10 11:21:55

标签: xml oracle oracle11g hierarchical-data

我正在尝试从Oracle创建一个XML,它们之间有父子关系。

表格数据如下所示。一个child_ID可以与一个或多个parent_ID相关联。 在此处,101与2个ID 100200相关联。

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生成计算containscontained_by

1 个答案:

答案 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>

享受!