从CLOB中的XML到包含路径列表的Oracle表
我使用的Oracle版本是:从CLOB中的XML到包含路径列表的Oracle表,xml,oracle,path,Xml,Oracle,Path,我使用的Oracle版本是: BANNER Oracle Database 10g Enterprise Edition Release 10.2.0.4.0 - 64bi PL/SQL Release 10.2.0.4.0 - Production CORE 10.2.0.4.0 Production TNS for IBM/AIX RISC System/6000: Version 10.2.0.4.0 - Productio NLSRTL Version 10.2.0.4.0 -
BANNER
Oracle Database 10g Enterprise Edition Release 10.2.0.4.0 - 64bi
PL/SQL Release 10.2.0.4.0 - Production
CORE 10.2.0.4.0 Production
TNS for IBM/AIX RISC System/6000: Version 10.2.0.4.0 - Productio
NLSRTL Version 10.2.0.4.0 - Production
在前面的问题中,我问过如何将clob转换为表,请参见:
我得到的答案很好,它适用于不太大的XML
但是,如果我有一个名为MY_table_ONE的表,其中有一个名为MY_field的字段,该字段是一个包含非常大的内容(例如500 KB)的CLOB,那么以下语句在合理的时间内不会退出:
CREATE TABLE MY_TABLE_TWO
AS
WITH PARAMS AS (SELECT XMLTYPE (MY_FIELD) FROM MY_TABLE_ONE)
SELECT ELEMENT_PATH, ELEMENT_TEXT
FROM XMLTABLE (
'
for $i in $doc/descendant-or-self::*
return <element>
<element_path> {$i/string-join(ancestor-or-self::*/name(.), ''/'')} </element_path>
<element_content> {$i/text()}</element_content>
</element>
'
PASSING (SELECT * FROM PARAMS) AS "doc"
COLUMNS ELEMENT_PATH VARCHAR2 (4000) PATH '//element_path',
ELEMENT_TEXT VARCHAR2 (4000) PATH '//element_content'
);
是否有其他方法可以更有效地转换存储在CLOB列中的XML,该列位于Oracle表中,包含路径列表和相应的值
上述说法是正确的,但需要太多时间才能最终确定
非常感谢您考虑我的请求
编辑:
我尝试过这个迭代解决方案,但没有成功:-
BEGIN
DECLARE
CURSOR S_CUR
IS
WITH PARAMS AS (SELECT XMLTYPE (MY_FIELD) FROM MY_TABLE_ONE)
SELECT ELEMENT_PATH, ELEMENT_TEXT
FROM XMLTABLE (
'
for $i in $doc/descendant-or-self::*
return <element>
<element_path> {$i/string-join(ancestor-or-self::*/name(.), ''/'')} </element_path>
<element_content> {$i/text()}</element_content>
</element>
'
PASSING (SELECT * FROM PARAMS where rownum < 101) AS "doc"
COLUMNS ELEMENT_PATH VARCHAR2 (4000) PATH '//element_path',
ELEMENT_TEXT VARCHAR2 (4000) PATH '//element_content'
);
TYPE FETCH_ARRAY IS TABLE OF S_CUR%ROWTYPE;
S_ARRAY FETCH_ARRAY;
BEGIN
EXECUTE IMMEDIATE 'ALTER SESSION SET DB_FILE_MULTIBLOCK_READ_COUNT=256';
EXECUTE IMMEDIATE 'TRUNCATE TABLE GOOFY99 DROP STORAGE';
OPEN S_CUR;
LOOP
FETCH S_CUR
BULK COLLECT INTO S_ARRAY
LIMIT 500;
FORALL I IN 1 .. S_ARRAY.COUNT
INSERT /*+APPEND */
INTO GOOFY99
VALUES S_ARRAY (I);
COMMIT;
EXIT WHEN S_CUR%NOTFOUND;
END LOOP;
CLOSE S_CUR;
COMMIT;
END;
END;
UPD我发现相当大的xml文件140 KB。我的系统:笔记本电脑,核心i5处理器2400 MHz,oracle 12c在虚拟机中,处理时间-0.38秒。
这种方法是我所知道的唯一的选择。我在w3schools.com上找到的xml示例
declare
xml_str clob := q'[<?xml version="1.0" encoding="UTF-8"?>
<CATALOG>
<CD>
<TITLE>Empire Burlesque</TITLE>
<ARTIST>Bob Dylan</ARTIST>
<COUNTRY>USA</COUNTRY>
<COMPANY>Columbia</COMPANY>
<PRICE>10.90</PRICE>
<YEAR>1985</YEAR>
</CD>
<CD>
<TITLE>Hide your heart</TITLE>
<ARTIST>Bonnie Tyler</ARTIST>
<COUNTRY>UK</COUNTRY>
<COMPANY>CBS Records</COMPANY>
<PRICE>9.90</PRICE>
<YEAR>1988</YEAR>
</CD>
</CATALOG>]';
v_doc dbms_xmldom.domdocument;
node dbms_xmldom.domnode;
txt varchar2(4000);
type t_list is table of number index by varchar2(4000);
v_list t_list;
procedure enum_nodes(n dbms_xmldom.domnode, tag_name varchar2) is
chn dbms_xmldom.domnode;
nl dbms_xmldom.domnodelist;
begin
nl := dbms_xmldom.getchildnodes(n);
for i in 0..dbms_xmldom.getlength(nl) loop
chn := dbms_xmldom.item(nl, i);
if dbms_xmldom.getnodetype(chn) = 1 then
enum_nodes(chn, tag_name || dbms_xmldom.getnodeName(chn) || '/');
elsif dbms_xmldom.getnodetype(chn) = 3 then
v_list(tag_name || dbms_xmldom.getnodevalue(chn)) := 1;
end if;
end loop;
end;
begin
v_doc := dbms_xmldom.newdomdocument(xml_str);
node := dbms_xmldom.makenode(v_doc);
enum_nodes(node, '/');
txt := v_list.first;
while txt is not null loop
dbms_output.put_line(txt);
txt := v_list.next(txt);
end loop;
end;
/
请你把这个有问题的大XML文件发到什么地方好吗?我不想这么说,但我还不知道XmlQuery语法,因此我无法从select中反向工程您的XML结构。XML包含保留数据和标记,因此我必须在发布到internet之前对其进行修改。。。不是那么直接!理解。不着急,我在12.1.0.2EE上对构建为xmltypecursorselect*的XML数据进行了测试,这些XML数据来自dba_对象,总共有46MB的XML数据存储在离线CLOB中。您的第一个查询创建表MY\u TABLE\u TWO作为。。。跑了11.5秒。我将在11.2xe.11.2xe上尝试同样的方法,相同的XML构造总共有6.5MB的XML数据,创建表在90秒内运行。我想,离您的问题越来越近了。输出是:/CATALOG/CD/ARTIST/text/CATALOG/CD/COMPANY/text/CATALOG/CD/COUNTRY/text/CATALOG/CD/PRICE/text/CATALOG/CD/TITLE/text/CATALOG/CD/YEAR/text为什么???很抱歉,据我所知,您需要像这里的示例中那样的输出:。我刚刚获取了另一个xml文件。您需要什么输出?我不需要文本,而是需要每个级别的值。有没有办法将路径和值显示到两个单独的字段中?现在,我正在使用500字节的XML来测试代码…@UltraCommit谢谢!:Path-在过程enum_节点的变量tag_名称中,value-是dbms_xmldom.getnodevaluechn的结果。可以单独累积它们,但需要进行一些更改。在这里,我使用类型为t_list的索引表变量v_list及其属性来仅具有唯一的索引。这里只能有一个索引,所以您需要使用另一个结构来累积值,然后选择unique。