如何将XML中的分层数据插入到oracle表中

时间:2017-12-11 13:02:31

标签: oracle plsql

我有一种情况是我必须从xmltype读取分层数据并将其插入到不同的表中。流动是xml样本。

<AH0>
    <AH1 ds="Root Hierarchy" id="1" primary="1">
        <AC ds="Org" id="Org">
            <AC ds="Org-CO" id="Org-CO">
                <AC ds="Org-CO-D01" id="Org-CO-D01">
                    <AC ds="Org-CO-D01-G66" id="Org-CO-D01-G66">
                        <AC ds="Org-CO-D01-G66-Z0081" id="Org-CO-D01-G66-Z0081">
                            <AC ds="Org-CO-D01-G66-Z0081-R80" id="Org-CO-D01-G66-Z0081-R80">
                                <AC ds="Org-CO-D01-G66-Z0081-R80-DS01" id="Org-CO-D01-G66-Z0081-R80-DS01">
                                    <AS ds="000099" id="99"/>
                                </AC>
                            </AC>
                            <AC ds="Org-CO-D01-G66-Z0081-R85" id="Org-CO-D01-G66-Z0081-R85">
                                <AC ds="Org-CO-D01-G66-Z0081-R85-DS01" id="Org-CO-D01-G66-Z0081-R85-DS01">
                                    <AS ds="000020" id="20"/>
                                </AC>
                            </AC>
                        </AC>
                    </AC>
                </AC>
            </AC>
            <AC ds="Org-FR" id="Org-FR">
                <AC ds="Org-FR-D06" id="Org-FR-D06">
                    <AC ds="Org-FR-D06-G05" id="Org-FR-D06-G05">
                        <AC ds="Org-FR-D06-G05-Z0008" id="Org-FR-D06-G05-Z0008">
                            <AC ds="Org-FR-D06-G05-Z0008-R244-2819" id="Org-FR-D06-G05-Z0008-R244-2819">
                                <AC ds="Org-FR-D06-G05-Z0008-R244-2819-DS01" id="Org-FR-D06-G05-Z0008-R244-2819-DS01">
                                    <AS ds="000489" id="489"/>
                                    <AS ds="000499" id="499"/>
                                    <AS ds="003439" id="3439"/>
                                </AC>
                                <AC ds="Org-FR-D06-G05-Z0008-R244-2819-DS05" id="Org-FR-D06-G05-Z0008-R244-2819-DS05">
                                    <AS ds="000467" id="467"/>
                                </AC>
                            </AC>
                        </AC>
                        <AC ds="Org-FR-D06-G05-Z1008" id="Org-FR-D06-G05-Z1008">
                            <AC ds="Org-FR-D06-G05-Z1008-R1008" id="Org-FR-D06-G05-Z1008-R1008">
                                <AC ds="Org-FR-D06-G05-Z1008-R1008-DS01" id="Org-FR-D06-G05-Z1008-R1008-DS01">
                                    <AS ds="000461" id="461"/>
                                    <AS ds="000554" id="554"/>
                                </AC>
                            </AC>
                        </AC>
                    </AC>
                </AC>
            </AC>
        </AC>
    </AH1>
</AH0>

我尝试使用以下代码,但它适用于固定层次结构。我需要的是它必须为第n级工作,以便可以删除代码的限制。

FOR rec_1 IN (SELECT ExtractValue(column_value, '/AC/@ds') as ds, ExtractValue(column_value, '/AC/@t') as t, ExtractValue(column_value, '/AC/@id') as id, EXTRACT(VALUE(P), '/AC') AS child
                    FROM TABLE(XMLSequence(XML_data.extract('//AC[@ds = "' || PARENTIDS || '"]/AC'))) p)
  LOOP

    --INSERTION PART 1
    FOR rec_t IN (SELECT ExtractValue(column_value, '/AC/@ds') as ds, ExtractValue(column_value, '/AC/@t') as t, ExtractValue(column_value, '/AC/@id') as id,
                         ExtractValue(column_value, '/AC/@l') as l, ExtractValue(column_value, '/AC/@cd') as cd, EXTRACT(VALUE(P), '/AC') AS child
                    FROM TABLE(XMLSequence(child.extract('//AC[@ds = "' || rec_1.id || '"]/AC'))) p)
    LOOP
    --INSERTION PART 2
    END LOOP;
  END LOOP;

1 个答案:

答案 0 :(得分:1)

我确信有更优雅的方式来做到这一点,但这是我想出的第一件事。内部查询展平xml层次结构,外部查询将值选为单独的列。

insert into my_table (ds, parent_ds)
    select xmlquery('//node[$l]/ds/text()' passing flat, level as "l" returning content) as ds,
        xmlquery('//node[$l]/parent/text()' passing flat, level as "l" returning content) as parent_ds
    from (
        select xmlquery(
            'for $x in .//AC
            return <node><ds>{data($x/@ds)}</ds><parent>{data($x/../@ds)}</parent></node>' 
            passing xmltype(column_value) returning content) flat
        from dual
    )
    connect by level <= to_number(xmlquery('count(//node)' passing flat returning content)) 
;