【问题标题】:generate xml using oracle使用oracle生成xml
【发布时间】:2016-11-30 10:33:49
【问题描述】:

我有以下要使用 oracle 生成的 xml。

<Component ID="600564" asmid="1" def="FactSheet" type="Document">
    <Profile>
        <Port_ID>182</Port_ID>
        <Inception_Date>31 Dec 1998</Inception_Date>
    </Profile>
    <AverageAnnualReturns>
        <TableData>
            <Item>
                <ClassID>33</ClassID>
                <ClassName>A1USD</ClassName>
                <Superscript>2</Superscript>
                <Superscript_TCE/>              
            </Item>
            <Item>
                <ClassID>45</ClassID>
                <ClassName>I1EUR</ClassName>
                <Superscript>1,2</Superscript>
                <Superscript_TCE/>              
            </Item>
        </TableData>
        <SuppressLifeColumn>Yes</SuppressLifeColumn>
        <SuppressBenchColumn10yr>No</SuppressBenchColumn10yr>
        <SuppressBenchColumn5yr>No</SuppressBenchColumn5yr>
        <SuppressBenchColumn3yr>No</SuppressBenchColumn3yr>
        <SuppressBenchColumn1yr>No</SuppressBenchColumn1yr>
    </AverageAnnualReturns>
</Component>

如下查询个人资料

SELECT PCR.PORT_ID,  
to_char(p.port_start_dt, 'dd Mon yyyy') as INCEPTION_DATE 
FROM edp_admin.PORT_CLASS_REPORT PCR 
JOIN edp_admin.PORTFOLIO p on (PCR.PORT_ID = P.PORT_ID and PCR.CLASS_ID = P.BASE_CLASS_ID) 
where PCR.PORT_ID = 182 AND PCR.REPORT_ID = 472

AverageAnnualReturn 查询如下

SELECT distinct MPR.PORT_ID, 
MPR.CLASS_ID, 
MPR.CLASS_NAME, 
PCR.VALUE_NUM3 as RANK, 
NVL (NC.SUPERSCRIPT_TEXT,' ') as SUPERSCRIPT_TEXT 
FROM EDP_ADMIN.SYSTEM_VALUE PCR 
LEFT JOIN EDP_ADMIN.MPR_MIL_VIEW MPR ON (PCR.VALUE_NUM1 = MPR.PORT_ID AND PCR.VALUE_NUM2 = MPR.CLASS_ID AND MPR.CLASSIF_ID = 206) 
LEFT JOIN EDP_ADMIN.PORT_CLASS_YIELD PCY ON (PCR.VALUE_NUM1 = PCY.PORT_ID AND PCR.VALUE_NUM2 = PCY.CLASS_ID AND MPR.PROFILE_DATE = PCY.PORT_CLASS_YIELD_DT AND PCY.YIELD_ID = 6) 
LEFT JOIN EDP_ADMIN.PORTFOLIO_CLASS PC ON (PCR.VALUE_NUM1 = PC.PORT_ID AND PCR.VALUE_NUM2 = PC.CLASS_ID) 
LEFT JOIN EDP_ADMIN.PORT_CLASS_MKT_PRICE PCMP ON (PCR.VALUE_NUM1 = PCMP.PORT_ID AND PCR.VALUE_NUM2 = PCMP.CLASS_ID AND PCMP.MKT_PRICE_ID = 12 AND MPR.PROFILE_DATE = PCMP.PORT_CLA_MKT_PRICE_PER_END_DT) 
LEFT JOIN (SELECT DISTINCT R1.PORT_ID, R1.CLASS_ID, R1.PORT_CLASS_EXP_RAT_VALUE, R1.PORT_CLASS_EXP_RAT_DT FROM edp_admin.Port_Class_Expense_Ratio R1 INNER JOIN (SELECT DISTINCT PORT_ID, CLASS_ID, MAX(PORT_CLASS_EXP_RAT_DT) as MONTH_END_DATE FROM EDP_ADMIN.PORT_CLASS_EXPENSE_RATIO GROUP BY PORT_ID, CLASS_ID ) R2 ON (R1.PORT_ID = R2.PORT_ID AND R1.CLASS_ID = R2.CLASS_ID AND R1.PORT_CLASS_EXP_RAT_DT = R2.MONTH_END_DATE) ) PCER ON PCR.VALUE_NUM1 = PCER.PORT_ID and PCR.VALUE_NUM2 = PCER.CLASS_ID 
LEFT JOIN EDP_ADMIN.FN_MIL_FS_CONCAT_NOTES_VIEW NC ON NC.PORT_ID = PCR.VALUE_NUM1 AND NC.CLASS_ID = PCR.VALUE_NUM2 AND NC.HYPO_TYPE = PCR.VALUE_CHAR1 
WHERE PCR.CODE = 'MIL_FS_PERF_CONFIG' AND PCR.VALUE_NUM1 IN (182) AND PCR.VALUE_CHAR1 = 'UK' ORDER BY RANK

我尝试使用 oracle sql 函数来生成如下所示的 xml

select dbms_xmlquery.getxml(sql for profile) from dual

但它会生成两个额外的 xml 节点行集和行,如下所示

<?xml version = '1.0'?>
<ROWSET>
   <ROW num="1">
      <PORT_ID>182</PORT_ID>
      <INCEPTION_DATE>31 Dec 1998</INCEPTION_DATE>      
   </ROW>
</ROWSET>

其他方式是

select xmlelement("Component",xmlattributes('600564' as ID,
                                             '1' as asmid,
                                             'FactSheet' as def,
                                             'Document' as type
                                             ),
                  xmlagg(
                  xmlelement("Profile")

                  )                                            

            )from dual

生成如下结构

<Component ID="600564" ASMID="1" DEF="FactSheet" TYPE="Document"><Profile></Profile></Component>

但是我不知道如何在profile 节点下填充数据,然后在averageannualreturns 下填充数据

【问题讨论】:

    标签: xml oracle plsql


    【解决方案1】:

    您可以使用子选择来获取profileaverageannualreturns 节点的数据。例如:

    select xmlelement("Component",
             xmlattributes('600564' as ID,
                           '1' as asmid,
                           'FactSheet' as def,
                           'Document' as type
             ),
            (
             SELECT XMLELEMENT("Profile",
                      XMLFOREST(
                        'example_port' AS "Port_ID",  
                        '30/11/2016' as "Inception_Date" 
                      )
                    )
             FROM dual
            )                                 
    ) from dual;
    

    我相信这是你需要的东西(虽然我没有你的表可以测试):

    select xmlelement("Component",
             xmlattributes('600564' as ID,
                           '1' as asmid,
                           'FactSheet' as def,
                           'Document' as type
             ),
            (
             SELECT XMLELEMENT("Profile",
                      XMLFOREST(
                        PCR.PORT_ID AS "Port_ID",  
                        to_char(p.port_start_dt, 'dd Mon yyyy') as "Inception_Date" 
                      )
                    )
             FROM edp_admin.PORT_CLASS_REPORT PCR 
             JOIN edp_admin.PORTFOLIO p on (PCR.PORT_ID = P.PORT_ID and PCR.CLASS_ID = P.BASE_CLASS_ID) 
             where PCR.PORT_ID = 182 AND PCR.REPORT_ID = 472
            ),
            (
              SELECT XMLELEMENT("AverageAnnualReturns",
                       XMLELEMENT("TableData",
                         XMLAGG(
                           XMLELEMENT("Item",
                             XMLFOREST(
                               MPR.CLASS_ID AS "ClassID",
                               MPR.CLASS_NAME AS "ClassName",
                               NVL (NC.SUPERSCRIPT_TEXT,' ') AS "SuperScript",
                               NULL AS "SuperScript_TCE"
                             )
                           )
                         )
                       ),
                       XMLFOREST(
                         'Yes' AS "SupressLifeColumn",
                         'No' AS "SupressBenchColumn10yr",
                         'No' AS "SupressBenchColumn5yr",
                         'No' AS "SupressBenchColumn3yr",
                         'No' AS "SupressBenchColumn1yr"
                       )
                     )
              FROM EDP_ADMIN.SYSTEM_VALUE PCR 
              LEFT JOIN EDP_ADMIN.MPR_MIL_VIEW MPR ON (PCR.VALUE_NUM1 = MPR.PORT_ID AND PCR.VALUE_NUM2 = MPR.CLASS_ID AND MPR.CLASSIF_ID = 206) 
              LEFT JOIN EDP_ADMIN.PORT_CLASS_YIELD PCY ON (PCR.VALUE_NUM1 = PCY.PORT_ID AND PCR.VALUE_NUM2 = PCY.CLASS_ID AND MPR.PROFILE_DATE = PCY.PORT_CLASS_YIELD_DT AND PCY.YIELD_ID = 6) 
              LEFT JOIN EDP_ADMIN.PORTFOLIO_CLASS PC ON (PCR.VALUE_NUM1 = PC.PORT_ID AND PCR.VALUE_NUM2 = PC.CLASS_ID) 
              LEFT JOIN EDP_ADMIN.PORT_CLASS_MKT_PRICE PCMP ON (PCR.VALUE_NUM1 = PCMP.PORT_ID AND PCR.VALUE_NUM2 = PCMP.CLASS_ID AND PCMP.MKT_PRICE_ID = 12 AND MPR.PROFILE_DATE = PCMP.PORT_CLA_MKT_PRICE_PER_END_DT) 
              LEFT JOIN (SELECT DISTINCT R1.PORT_ID, R1.CLASS_ID, R1.PORT_CLASS_EXP_RAT_VALUE, R1.PORT_CLASS_EXP_RAT_DT FROM edp_admin.Port_Class_Expense_Ratio R1 INNER JOIN (SELECT DISTINCT PORT_ID, CLASS_ID, MAX(PORT_CLASS_EXP_RAT_DT) as MONTH_END_DATE FROM EDP_ADMIN.PORT_CLASS_EXPENSE_RATIO GROUP BY PORT_ID, CLASS_ID ) R2 ON (R1.PORT_ID = R2.PORT_ID AND R1.CLASS_ID = R2.CLASS_ID AND R1.PORT_CLASS_EXP_RAT_DT = R2.MONTH_END_DATE) ) PCER ON PCR.VALUE_NUM1 = PCER.PORT_ID and PCR.VALUE_NUM2 = PCER.CLASS_ID 
              LEFT JOIN EDP_ADMIN.FN_MIL_FS_CONCAT_NOTES_VIEW NC ON NC.PORT_ID = PCR.VALUE_NUM1 AND NC.CLASS_ID = PCR.VALUE_NUM2 AND NC.HYPO_TYPE = PCR.VALUE_CHAR1 
              WHERE PCR.CODE = 'MIL_FS_PERF_CONFIG' AND PCR.VALUE_NUM1 IN (182) AND PCR.VALUE_CHAR1 = 'UK' ORDER BY RANK   
            )                                   
    ) from dual;
    

    使用 appendChildXML 和 plsql 的解决方案:

    DECLARE
      lComponentXML xmltype;
      lProfileXML   xmltype;
    BEGIN
      --generate the component xml
      select xmlelement("Component",
               xmlattributes('600564' as ID,
                             '1' as asmid,
                             'FactSheet' as def,
                             'Document' as type
               )
             )
      INTO lComponentXML
      FROM dual;
    
      --generate the profile xml
      SELECT XMLELEMENT("Profile",
               XMLFOREST(
                 PCR.PORT_ID AS "Port_ID",  
                 to_char(p.port_start_dt, 'dd Mon yyyy') as "Inception_Date"
               )
             )
      INTO lProfileXML
      FROM edp_admin.PORT_CLASS_REPORT PCR 
      JOIN edp_admin.PORTFOLIO p on (PCR.PORT_ID = P.PORT_ID and PCR.CLASS_ID = P.BASE_CLASS_ID) 
      where PCR.PORT_ID = 182 AND PCR.REPORT_ID = 472;
    
      --append the profile xml to the component
      lComponentXML := lComponentXML.appendChildXML('//Component',lProfileXML);
    END;
    

    【讨论】:

    • 它有效,但如果我在 sql 中使用 distinct 或 order by 则无效。在 AverageAnnulReturns 的 sql 中,使用了 distinct 和 order by,但执行失败
    • 一件事也是我最关心的问题,在生成每个 sql 的 xml 等效结构之前,我将如何将业务条件应用于它。
    • 如果您使用的是 plsql,我添加了一个额外的解决方案,允许您在将其附加到主要 XML 正文之前围绕 XML 应用业务条件。我可能只是建议单独构建每个 XML 块,然后逐渐附加它。这样,您可以使用 order by 和 distinct 子句让每个小块工作,并逐渐将它们添加到
    • 不,即使我单独执行这些子选择,也不支持 distinct ,将错误视为缺少表达式。
    • 不幸的是,如果没有您的表结构、任何示例数据或您尝试运行以生成 XML 的查询,我将很难提供帮助。唯一想到的是使用with ... as 语句。即with annual_returns as 然后您现有的查询使用 distinct 和 order by 子句。然后,您可以查询 Annual_returns 以生成 XML。
    猜你喜欢
    • 1970-01-01
    • 2014-03-22
    • 2013-10-14
    • 1970-01-01
    • 1970-01-01
    • 2014-03-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多