2016-02-27 1 views
0

У нас есть таблица под названием audit1. Он содержит столбцы «изменения», содержащие XML как blob. Xml выглядит следующим образом. В таблице аудита в основном записываются изменения, которые происходят с другими таблицами через пользовательский интерфейс нашего приложения.Oracle - Итерация по XMLTYPE и возвращаемым узлам в виде отдельных строк

<c> 
    <f n="VersNo" b="1" a="2"/> 
    <f n="LstDate" b="20160215" a="20160217"/> 
    <f n="FileSweepId" b="Test" a="Test1"/> 
</c> 
  • гр выступает за изменения
  • F выступает за полем
  • н атрибут обозначает имя (как в имени поля)
  • б обозначает до значения
  • А означает после значения

Мне нужно создать отчет, в котором перечислены все произошедшие изменения красный с определенной даты до определенных таблиц. Как только у меня есть записи audit1, которые меня интересуют, мне нужно перечислить все узлы f в отчете.

Это каждый f-узел в каждой соответствующей записи аудита должен стать строкой в ​​отчете.

Отчет подготовлен при помощи нашего приложения. Что приложение может предпринять для создания отчета является один из следующих:

  1. SQL-запросов
  2. или имя хранимой процедуры, которая должна вернуть результат в SYS реф курсором, который будет передан в порядке когда приложение вызывает его. Курсор ref будет вызываться out_cursor.

Я не могу придумать способ достижения этого с помощью одного запроса sql. Итак, я иду по пути записи хранимой процедуры.

  1. Первой проблемой, с которой я столкнулся, является то, как перебирать узлы f в процедуре.

  2. Во-вторых, мне нужно выяснить, как вернуть эти f-узлы вместе с другой информацией из записей аудита в out_cursor.

     
    BEGIN 
        FOR item IN (SELECT auditno, xmltype(changes, 1) as changes, extract(xmltype(changes, 1), '/c/f') as fields from audit1 where runlistno is null and rownum < 2) 
         LOOP 
         dbms_output.put_line(item.auditno || ' ' || item.changes.getStringVal() || ' ' || item.fields.getStringVal()); 
         -- stumped about how to iterate over the f nodes 
         --FOR field in ('select extractvalue(object_value, '/') x FROM TABLE(XMLSequence(' + item.fields.getStringVal() + ') ') 
        FOR field in (select f from XMLTable('for $i in/return $i' passing item.fields columns f varchar2(200) path 'f')) 
        LOOP 
        dbms_output.put_line(field.f); 
        END LOOP; 
    END LOOP; 
    END; 
    

выше PL/SQL, в настоящее время ошибок с:

ORA-19114: XPST0003 - ошибка во время синтаксического анализа выражения XQuery: LPX-00801: XQuery синтаксической ошибки в 'i' 1 для $ i in/return $ i -^ORA-06512: по строке 6

ответ

0

Почему бы вам не использовать простой SQL, с прикованными XMLTable функциями, которые извлекают обязательное для заполнения поля?
Посмотрите на простом примере:

CREATE TABLE audit1(
    changes CLOB 
); 

INSERT INTO audit1 VALUES('<c> 
    <f n="VersNo" b="1" a="2"/> 
    <f n="LstDate" b="20160215" a="20160217"/> 
    <f n="FileSweepId" b="Test" a="Test1"/> 
</c>' 
); 
INSERT INTO audit1 VALUES(
'<c> 
    <f n="VersNo" b="22" a="32"/> 
    <f n="LstDate" b="20160218" a="2016020"/> 
    <f n="FileSweepId" b="Test 555" a="Test1234"/> 
</c>' 
); 
commit; 

и теперь:

SELECT rec_no, rn, n, b, a 
FROM (select rownum rec_no, a.* FROM audit1 a), 
    XMLTable('/c' 
       passing xmltype(changes) 
       columns f_fields xmltype path './f' 
      ) x1, 
    XMLTable('/f' 
       passing x1.f_fields 
       columns rn for ordinality, 
         n varchar2(20) path './@n', 
         b varchar2(20) path './@b', 
         a varchar2(20) path './@a' 
       ) 

    REC_NO   RN N     B     A     
---------- ---------- -------------------- -------------------- -------------------- 
     1   1 VersNo    1     2      
     1   2 LstDate    20160215    20160217    
     1   3 FileSweepId   Test     Test1     
     2   1 VersNo    22     32     
     2   2 LstDate    20160218    2016020    
     2   3 FileSweepId   Test 555    Test1234    

6 rows selected 
0

Я смог избавиться o f ошибка, изменяя значение plsql:

BEGIN 
    FOR item IN (SELECT auditno, xmltype(changes, 1) as changes, extract(xmltype(changes, 1), '/c/f') as fields from audit1 where runlistno is null and rownum < 2) 
    LOOP 
    dbms_output.put_line('parsing fields from: ' || item.fields.getStringVal()); 
    dbms_output.put_line('name||beforevalue||aftervalue'); 
    FOR field in (select n, b, a from XMLTable('//f' passing item.fields columns n varchar2(30) path '@n', b varchar(30) path '@b', a varchar(30) path '@a')) 
     LOOP 
     dbms_output.put_line(field.n || '|| ' || field.b || '|| ' || field.a); 
    END LOOP; 
    END LOOP; 
END; 

Так что теперь я могу перебирать поля. Но пока не уверен, как я могу вернуть информацию из полей в курсе sys ref. Пример вывод сверху PLSQL:

parsing fields from: <f n="VersNo" b="1" a="2"/><f n="LstDate" b="20160215" a="20160217"/><f n="FileSweepId" b="Test" a="Test1"/> 
name||beforevalue||aftervalue 
VersNo|| 1|| 2 
LstDate|| 20160215|| 20160217 
FileSweepId|| Test|| Test1