生成Oracle XMLType,从触发器到高级队列具有空值

时间:2010-12-17 02:01:21

标签: xml oracle plsql oracle-aq

下午好。

我一直在使用Oracle Advanced Queues来创建一个消息传递系统,我们可以使用它来确定何时将新行传递到数据库,何时发生更新以及何时发生删除。

我正在使用单个使用者队列并使用相关性来控制在特定时间查找的数据,并且我的有效负载是xmltype。

为了生成xml,我最初使用xmlsequence来生成如下消息。

<MESSAGE>
<LOCATIONS>
  <LOCATION_ID>9999</LOCATION_ID>
  <LOC_TYPE>S</LOC_TYPE>
  <NAME>Test Location</NAME>
  <RETAILER_UNIT_CODE>T&amp;L</RETAILER_UNIT_CODE>
  <REGION_CODE>SA</REGION_CODE>
  <DELETE_FLAG>N</DELETE_FLAG>
  <EXTERNAL_WHSE_FLAG>N</EXTERNAL_WHSE_FLAG>
  <CREATED_BY>SYSADMIN</CREATED_BY>
  <CREATED_DATE>04/MAR/08</CREATED_DATE>
  <STATE_CODE>SA</STATE_CODE>
  <ADDRESS>223 Road Ridsonville</ADDRESS>
  <POSTCODE>1234</POSTCODE>
  <PHONE_NUM>08 </PHONE_NUM>
  <LAST_MODIFIED_BY>SYSADMIN</LAST_MODIFIED_BY>
  <LAST_MODIFIED_DATE>21/APR/09</LAST_MODIFIED_DATE>
  <POS_CODE>TRANS</POS_CODE>
  <SOP_FLAG>N</SOP_FLAG>
</LOCATIONS>
</MESSAGE>

然而,我注意到xmlsequence遗漏了空元素,这是不理想的,因为当需要在另一端拾取消息时,它们不能轻易地映射到数据字段。 为了解决这个问题,我试图在我的触发器中使用DBMS_XMLGEN,因为它允许以我希望它处理的方式处理空值。

ctx := dbms_xmlgen.newContext('SELECT * FROM LOCATIONS WHERE LOCATION_ID = ' || :new.LOCATION_ID);
dbms_xmlgen.setrowsettag(ctx, 'MESSAGE');
dbms_xmlgen.setrowtag(ctx, 'LOCATIONS');
dbms_xmlgen.setnullhandling(ctx, dbms_xmlgen.EMPTY_TAG);
l_xml:=dbms_xmlgen.getxmltype(ctx);

这种方法的问题在于它会产生一个异常,因为它试图在触发器执行的同一个表上运行。

ORA-04091: table RIT.LOCATIONS is mutating, trigger/function may not see it

所以我继续尝试使用新旧对象来获取数据并将其放入上下文中,但是我正在运行一些带有值为null的小问题,因为它们正在肆虐将我们连接到查询字符串中。

...
REFERENCING NEW AS NEW OLD AS OLD
for each row 
DECLARE
l_xml   xmltype;
ctx       dbms_xmlgen.ctxHandle;
begin
ctx := dbms_xmlgen.newContext('SELECT   '||:new.id||'as id, '||:new.nullfield||' as nullfield from dual');
dbms_xmlgen.setrowsettag(ctx, 'MESSAGE');
dbms_xmlgen.setrowtag(ctx, 'INT_CREDIT_CLAIMS');
dbms_xmlgen.setnullhandling(ctx, dbms_xmlgen.EMPTY_TAG);
l_xml:=dbms_xmlgen.getxmltype(ctx);
...
end;

所以我的问题是:我怎样才能解决这个问题,以便能看到我的xml类型的空元素?

我也愿意接受有关如何解决问题的建议,并将检查任何澄清请求。

1 个答案:

答案 0 :(得分:2)

要生成XML格式的简单行,您可以使用xmlelement

SQL> CREATE TABLE emp AS SELECT * FROM scott.emp;

Table created

SQL> CREATE TABLE message (xml XMLTYPE);

Table created

SQL> CREATE OR REPLACE TRIGGER trg_b4_emp
  2     BEFORE UPDATE ON emp
  3     FOR EACH ROW
  4  BEGIN
  5     INSERT INTO message VALUES (
  6       xmlelement("MESSAGE",
  7           xmlelement("EMP",
  8              xmlelement("empno", :new.empno),
  9              xmlelement("comm", :new.comm)
 10           )
 11        )
 12     );
 13  END;
 14  /

SQL> update emp set comm=NULL;

14 rows updated

SQL> select * from message where rownum = 1;

XML
----------------------------------------------------------------
<MESSAGE><EMP><empno>7369</empno><comm></comm></EMP></MESSAGE>