2014-11-05 2 views
4

Оракул Version Я использую это:С XML внутри CLOB, в 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 - Production 

В предыдущем вопросе, я спросил, как преобразовать CLOB в таблице, см это :

From XML to list of paths in Oracle PL/SQL environment

ответ, который я получил, был велик, и это работает для XML не слишком большой.

Но если у меня есть таблица под названием MY_TABLE_ONE с полем под названием MY_FIELD, который является CLOB с очень большим содержанием (например, 500 Кбайт), следующий оператор не выходит в течение разумного времени:

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' 
      ); 

Есть ли альтернативный способ преобразования XML, хранящегося в столбце CLOB, в таблицу Oracle со списком путей и соответствующих значений более эффективным образом?

Вышеприведенное заявление является правильным, но для его завершения требуется слишком много времени.

Большое спасибо за рассмотрение моей просьбы.

EDIT:.

Я пытался с этим итеративным решением, без успеха :-(

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; 
+0

Не могли бы вы разместить где-нибудь проблематично большой файл XML? (Мне не нравится это говорить, но я еще не знаю синтаксиса XmlQuery, поэтому я не могу перестроить структуру XML из вашего выбора.) – nop77svk

+0

XML содержит зарезервированные данные и теги, поэтому я должен изменить его перед публикацией в интернете ... Это не так сразу! – UltraCommit

+0

Понял. Не торопись. – nop77svk

ответ

2

UPD я нашел довольно большой файл XML (140 Кб) Мой кинозал: ноутбук с базовым процессором i5 (2400 МГц), oracle 12c внутри виртуальной машины, время обработки - 0,38 секунды. Этот метод является единственной альтернативой, которую я знаю. Пример xml здесь я нашел на w3schools.com.

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; 
/
+0

Вывод:/CATALOG/CD/ARTIST/text() /CATALOG/CD/COMPANY/text() /CATALOG/CD/COUNTRY/текст() /КАТАЛОГ/CD/ЦЕНА/текст() /КАТАЛОГ/CD/TITLE/текст() /CATALOG/CD/YEAR/text() Почему ??? – UltraCommit

+1

Извините, как я понял, вам нужен вывод, как в вашем примере: http://stackoverflow.com/questions/18146788/from-xml-to-list-of-paths-in-oracle-pl-sql-environment. Я просто взял еще один XML-файл. Какой результат вам нужен? – Dmitry

+0

Вместо текста() Мне нужно значение на каждом уровне. – UltraCommit

Смежные вопросы