0

我需要删除 XML 的某些部分(来自 DBMS_METADATA 的表定义)。找到 XMLPATCH 并使其适用于非常小的示例 XML。但我面临两个问题:一大一小。

  • 最大的问题是下面的查询填满了所有实例的 PGA (PGA_TARGET=8GB),如果我在带有表定义的真实 25KB XML 上使用它。
  • 小问题是我在 PL/SQL 中使用它,所以原生 PL/SQL 会比 SELECT FROM DUAL 更好;

有谁知道如何优化以下内容以正确删除 /ROWSET[1]/ROW[1]/TABLE_T[1]/CON1_LIST[1] 并使用最少的内存?

有谁知道如何将以下内容重写为 PL/SQL 代码?

SELECT XMLPATCH ( XMLTYPE( '<?xml version="1.0"?>
<ROWSET><ROW><TABLE_T><VERS_MAJOR>2</VERS_MAJOR><MAXTRANS>0</MAXTRANS>
<CON1_LIST><CON1_LIST_ITEM><OWNER_NUM>115</OWNER_NUM></CON1_LIST_ITEM></CON1_LIST>
<BHIBOUNDVAL empty="blob"/><PHYPART_NUM>10</PHYPART_NUM></TABLE_T></ROW></ROWSET>')
                , XMLTYPE( '<?xml version="1.0"?>
<xd:xdiff xsi:schemaLocation="http://xmlns.oracle.com/xdb/xdiff.xsd
 http://xmlns.oracle.com/xdb/xdiff.xsd"
 xmlns:xd="http://xmlns.oracle.com/xdb/xdiff.xsd"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <?oracle-xmldiff operations-in-docorder="true" output-model="snapshot" diff-algorithm="global"?>
    <xd:delete-node 
     xd:node-type="element" 
     xd:xpath="/ROWSET[1]/ROW[1]/TABLE_T[1]/CON1_LIST[1]"/>
</xd:xdiff>')
)
FROM DUAL;
```
4

2 回答 2

1

这个应该解决更大的问题,也应该更快:

select
     XMLQuery('copy $i := $p modify
                  delete nodes $i/ROWSET[1]/ROW[1]/TABLE_T[1]/CON1_LIST[1]
               return $i'
               PASSING XMLTYPE( '<?xml version="1.0"?>
                        <ROWSET>
                           <ROW>
                              <TABLE_T>
                                 <VERS_MAJOR>2</VERS_MAJOR>
                                 <MAXTRANS>0</MAXTRANS>
                                 <CON1_LIST>
                                     <CON1_LIST_ITEM>
                                        <OWNER_NUM>115</OWNER_NUM>
                                     </CON1_LIST_ITEM>
                                 </CON1_LIST>
                                 <BHIBOUNDVAL empty="blob"/>
                                 <PHYPART_NUM>10</PHYPART_NUM>
                              </TABLE_T>
                           </ROW>
                        </ROWSET>') AS "p" 
         RETURNING CONTENT
         ) xres
from dual;

不幸的是,我们仍然在 PL/SQL 中使用 SQL 来更新它:

declare
   x xmltype:= XMLTYPE( '<?xml version="1.0"?>
<ROWSET><ROW><TABLE_T><VERS_MAJOR>2</VERS_MAJOR><MAXTRANS>0</MAXTRANS>
<CON1_LIST><CON1_LIST_ITEM><OWNER_NUM>115</OWNER_NUM></CON1_LIST_ITEM></CON1_LIST>
<BHIBOUNDVAL empty="blob"/><PHYPART_NUM>10</PHYPART_NUM></TABLE_T></ROW></ROWSET>');
   res xmltype;
   g_doc dbms_xmldom.DOMDocument; -- basic DOM-document
   g_node dbms_xmldom.DOMNode;
 
begin
   select
      XMLQuery('copy $i := $p modify
                  delete nodes $i/ROWSET[1]/ROW[1]/TABLE_T[1]/CON1_LIST[1]
               return $i'
               PASSING x AS "p" 
         RETURNING CONTENT
         )
      into res
   from dual;
   dbms_output.put_line(res.getclobval());
end;
/
于 2020-07-23T09:59:49.217 回答
0

DELETEXML 也是一个答案:

WITH base
AS ( SELECT '<?xml version="1.0"?><ROWSET><ROW>
  <TABLE_T><VERS_MAJOR>2</VERS_MAJOR><MAXTRANS>0</MAXTRANS>
  "<CON1_LIST><CON1_LIST_ITEM><OWNER_NUM>115</OWNER_NUM></CON1_LIST_ITEM></CON1_LIST>"
  <BHIBOUNDVAL empty="blob"/><PHYPART_NUM>10</PHYPART_NUM></TABLE_T></ROW></ROWSET>' xml_data
  FROM dual 
   )
SELECT base.xml_data
     , XMLSERIALIZE( CONTENT DELETEXML(XMLTYPE(base.xml_data), '/ROWSET[1]/ROW[1]/TABLE_T[1]/CON1_LIST[1]') INDENT SIZE=2) xres
FROM base
;

...但它已被弃用,所以Sayan的解决方案更好。

于 2020-07-23T12:26:51.330 回答