在Oracle中读取嵌套XML(SQL)

问题描述 投票:3回答:1
<detailedOutput>
                <entity>
                    <entityLabel>Policy Holder 1</entityLabel>
                    <entityName>PHN.1</entityName>
                    <entityType>Policy Holder Name</entityType>
                    <fact>
                        <name>fired</name>
                        <nameContents>Y</nameContents>
                        <messageCode>M003</messageCode>
                        <reported>Y</reported>
                        <uniqueID>C_9_3_1</uniqueID>
                        <instanceID>1.1</instanceID>
                    </fact>
                    <fact>
                        <name>fired</name>
                        <nameContents>Y</nameContents>
                        <messageCode>M010</messageCode>
                        <reported>Y</reported>
                        <uniqueID>C_4_3_1</uniqueID>
                        <instanceID>1.1</instanceID>
                    </fact>
                </entity>
                <entity>
                    <entityLabel>property</entityLabel>
                    <entityName>PROP.1</entityName>
                    <entityType>Property</entityType>
                    <fact>
                        <name>propertyAddress</name>
                        <nameContents>1280 Somewhere Street, San Diego, WA 98312</nameContents>
                    </fact>
                    <fact>
                        <name>inqZipCode</name>
                        <nameContents>98312</nameContents>
                    </fact>
</detailedOutput>

我有这样的XML,我需要读取所有值并将其存储在SQL中的表中。我跟随我的代码:

for rec_facts in (
    select EXTRACTVALUE(VALUE(TAB),'/entity/entityLabel/text()') as entity_label
        ,EXTRACTVALUE(VALUE(TAB),'/entity/entityName/text()') as entity_name
        ,EXTRACTVALUE(VALUE(TAB),'/entity/entityType/text()') as entity_type
        FROM TABLE(XMLSEQUENCE(EXTRACT(SYS.XMLTYPE(v_xmltype),'/creditBureau/product/custom/riskVerificationPlatform/detailedOutput/entity'))) TAB
        union all 
        select null, null, null from dual where not exists (select 1 from table(xmlsequence(extract(sys.xmltype(v_xmltype),'/creditBureau/product/custom/riskVerificationPlatform/detailedOutput/entity')))TAB1)
)              
loop 
    for recout in (
        select EXTRACTVALUE(VALUE(TAB2),'/fact/name/text()') as fact_name
            ,EXTRACTVALUE(VALUE(TAB2),'/fact/nameContents/text()') as fact_nameContents
            ,EXTRACTVALUE(VALUE(TAB2),'/fact/messageCode/text()') as fact_messageCode
            ,EXTRACTVALUE(VALUE(TAB2),'/fact/reported/text()') as fact_reported
            ,EXTRACTVALUE(VALUE(TAB2),'/fact/uniqueID/text()') as fact_uniqueID
            ,EXTRACTVALUE(VALUE(TAB2),'/fact/instanceID/text()') as fact_instanceID
            TABLE(XMLSEQUENCE(EXTRACT(SYS.XMLTYPE(v_xmltype),'/creditBureau/product/custom/riskVerificationPlatform/message'))) TAB2
            union all 
            select null, null, null, null, null, null from dual where not exists (select 1 from table(xmlsequence(extract(sys.xmltype(v_xmltype),'/creditBureau/product/custom/riskVerificationPlatform/message')))TAB2)
    )                                                                                                              
    loop 
        insert into TUNA_FACTS
            (TUNA_FACTS
            ,TUNA_WEB_REQUEST_RESPONSE
            ,ENTITY_LABEL
            ,ENTITY_NAME
            ,ENTITY_TYPE
            ,FACT_NAME
            ,FACT_NAMECONTENTS
            ,FACT_MESSAGECODE
            ,FACT_REPORTED
            ,FACT_UNIQUEID
            ,FACT_INSTANCEID
            ,CREATED_ON
            ,CREATED_BY
            ,AUDIT_ID
            )
            values 
            (seq_TUNA_FACTS.nextval
            ,v_seq_TUNA_web_req_res
            ,rec_facts.entity_label
            ,rec_facts.entity_name
            ,rec_facts.entity_type
            ,recout.fact_name
            ,recout.fact_nameContents
            ,recout.fact_messageCode
            ,recout.fact_reported
            ,recout.fact_uniqueID
            ,recout.fact_instanceID
            ,sysdate
            ,'TUNA'
            ,user);   
    end loop;
end loop;             

代码运行,但它重复每个entityLabel,entityName和entityType 4次而不是2次。例如,表应该是这样的:

entityLabel        entityName    entityType             FactName
---------------    ----------    ------------------     ---------------
Policy Holder 1    PHN.1         Policy Holder Name     fired
Policy Holder 1    PHN.1         Policy Holder Name     fired
property           PROP.1        Property               PropertyAddress
property           PROP.1        Property               inqZipCode

相反,它创建一个像这样的表:

entityLabel        entityName    entityType             FactName
---------------    ----------    ------------------     ---------------
Policy Holder 1    PHN.1         Policy Holder Name     fired
Policy Holder 1    PHN.1         Policy Holder Name     fired
Policy Holder 1    PHN.1         Policy Holder Name     PropertyAddress
Policy Holder 1    PHN.1         Policy Holder Name     inqZipCode
property           PROP.1        Property               fired
property           PROP.1        Property               fired
property           PROP.1        Property               PropertyAddress
property           PROP.1        Property               inqZipCode

我确信这是一个循环问题,但我无法弄清楚。任何帮助,将不胜感激!

sql xml oracle parsing nested-loops
1个回答
3
投票

for-loop构造在这里是多余的。单个select语句完全符合您的要求。 在下面的例子中,我使用了问题中提出的数据:

create table xmldata as
with xmldoc as (
select xmlType('
    <detailedOutput>
    <entity>
        <entityLabel>Policy Holder 1</entityLabel>
        <entityName>PHN.1</entityName>
        <entityType>Policy Holder Name</entityType>
        <fact>
            <name>fired</name>
            <nameContents>Y</nameContents>
            <messageCode>M003</messageCode>
            <reported>Y</reported>
            <uniqueID>C_9_3_1</uniqueID>
            <instanceID>1.1</instanceID>
        </fact>
        <fact>
            <name>fired</name>
            <nameContents>Y</nameContents>
            <messageCode>M010</messageCode>
            <reported>Y</reported>
            <uniqueID>C_4_3_1</uniqueID>
            <instanceID>1.1</instanceID>
        </fact>
    </entity>
    <entity>
        <entityLabel>property</entityLabel>
        <entityName>PROP.1</entityName>
        <entityType>Property</entityType>
        <fact>
            <name>propertyAddress</name>
            <nameContents>1280 Somewhere Street, San Diego, WA 98312</nameContents>
        </fact>
        <fact>
            <name>inqZipCode</name>
            <nameContents>98312</nameContents>
        </fact>
    </entity>
    </detailedOutput>
    ') xml from dual
)
select xml from xmldoc
/

Table XMLDATA created.

extract()xmlSequence的声明:

select
    extractValue (value(e), '/entity/entityLabel') as "entityLabel",
    extractValue (value(e), '/entity/entityName')  as "entityName",
    extractValue (value(e), '/entity/entityType')  as "entityType",
    extractValue (value(f), '/fact/name')          as "factName" 
from xmldata x,
    table (xmlSequence(extract(xml,      '/detailedOutput/entity'))) e,
    table (xmlSequence(extract(value(e), '/entity/fact'))) f
/

还要考虑xmlSequence一直是deprecated,而且应该使用xmlTable代替:

select e."entityLabel", e."entityName", e."entityType", f."factName"
from xmldata x cross join  
xmlTable ('/detailedOutput/entity' passing x.xml columns
    "entityLabel" varchar2(32) path '/entity/entityLabel',
    "entityName"  varchar2(32) path '/entity/entityName',
    "entityType"  varchar2(32) path '/entity/entityType',
    facts         xmlType      path 'fact'
) e cross join
xmlTable ('fact' passing e.facts columns
    "factName" varchar2(32) path '/fact/name' 
) f
/

这两个语句的输出是相同的:

entityLabel      entityName       entityType               factName
---------------- ---------------- ------------------------ ----------------
Policy Holder 1  PHN.1            Policy Holder Name       fired
Policy Holder 1  PHN.1            Policy Holder Name       fired
property         PROP.1           Property                 propertyAddress
property         PROP.1           Property                 inqZipCode

4 rows selected.

现在PL / SQL块可能看起来很简单:

create view tuna_facts_view as <one of both selects suggested above>;
create table tuna_facts as select * from tuna_facts_view where 1=0;
declare 
    function insertTunaFacts return integer is
    begin
        insert into tuna_facts select * from tuna_facts_view;
        return sql%rowcount;
    end insertTunaFacts;
begin 
    dbms_output.put_line ('inserted rows '||insertTunaFacts ());    
end;
/

PL/SQL procedure successfully completed.

inserted rows 4
© www.soinside.com 2019 - 2024. All rights reserved.