2016-02-27 89 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> 
  • c代表變化
  • f代表場
  • n屬性代表名稱(在字段的名字作爲)
  • b表示值之前
  • a代表值

我需要創建一個報告,列出所有已發生的變化自給定日期後到某些表格爲紅色。一旦我有我感興趣的audit1記錄,我需要列出報告中的所有f個節點。

即每個相關審計記錄中的每個f節點都需要成爲報表中的一行。

該報告由我們的應用程序生成。哪些應用程序可以用於生成報告是下列之一:

  1. 一個SQL查詢
  2. 或必須在其中將被傳遞到過程的SYS REF光標返回其結果的存儲過程的名稱當應用程序調用它。引用遊標將被稱爲out_cursor。

我想不出一種通過單個SQL查詢來實現這一點的方法。所以,我正在寫一個存儲過程。

  1. 我面臨的第一個問題是如何迭代過程中的f個節點。

  2. 其次,我需要弄清楚如何返回這些f節點以及來自out_cursor中審計記錄的其他信息。在XQuery的語法錯誤: LPX-00801:錯誤解析所述XQuery表達式時 - XPST0003:

    ORA-19114:

     
    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 'i'1 for $ i in/return $ i -^ORA-06512:at line 6

回答

0

你爲什麼不使用簡單的SQL,用鏈式XMLTable函數提取reqired領域?
看簡單的例子:

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; 

所以我現在能夠遍歷字段。但不知道如何我可以返回系統參考遊標中的字段的信息。從上面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