PL/SQL 中的 XMLPATCH?
XMLPATCH in PL/SQL?
我需要删除 XML 的某些部分(DBMS_METADATA 中的 table 定义)。找到 XMLPATCH 并使其适用于非常小的,例如下面的 XML。但是我面临一大一小两个问题
- 最大的问题是下面的查询填满了实例的所有 PGA (PGA_TARGET=8GB),如果我在真实情况下使用它,25KB XML 定义为 table。
- 小问题是我在 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;
```
这个应该可以解决更大的问题,而且速度应该更快:
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;
/
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 的解决方案更好。
我需要删除 XML 的某些部分(DBMS_METADATA 中的 table 定义)。找到 XMLPATCH 并使其适用于非常小的,例如下面的 XML。但是我面临一大一小两个问题
- 最大的问题是下面的查询填满了实例的所有 PGA (PGA_TARGET=8GB),如果我在真实情况下使用它,25KB XML 定义为 table。
- 小问题是我在 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;
```
这个应该可以解决更大的问题,而且速度应该更快:
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;
/
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 的解决方案更好。