Oracle - 迭代XMLTYPE并将节点作为单独行返回

时间:2016-02-27 19:35:19

标签: sql oracle plsql

我们有一个名为audit1的表。它有一个列'更改',其中包含XML作为blob。 xml如下所示。审计表基本上记录了通过我们的应用程序UI发生在其他表上的更改。

<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游标中返回其结果的存储过程的名称,该游标将在应用程序调用它时传递给过程。 ref游标将被称为out_cursor。
  3. 我想不出通过单个sql查询实现这一目标的方法。所以,我正在写一个存储过程的道路。

    1. 我面临的第一个问题是如何迭代过程中的f个节点。

    2. 其次,我需要弄清楚如何从out_cursor中的审计记录返回这些f节点以及其他信息。

      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;
      

    3. 上面的PL / SQL目前错误:

        

      ORA-19114:XPST0003 - 解析XQuery表达式时出错:   LPX-00801:$ i中的$ i in / return $ i的XQuery语法错误    - ^ ORA-06512:第6行

2 个答案:

答案 0 :(得分:0)

我能够通过将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

答案 1 :(得分: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