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

发布于 2024-10-08 17:00:11 字数 2315 浏览 1 评论 0原文

下午好。

我一直在与 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 遗漏了 null 元素,这并不理想,因为当需要在另一端拾取消息时,它们无法轻松映射到数据字段上。 为了尝试解决这个问题,我尝试在触发器中使用 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

因此,我继续尝试使用新对象和旧对象来获取数据并将其放入上下文中,但是我遇到了一些空值的问题,因为它们对我的串联造成了严重破坏将它们添加到查询字符串中。

...
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 类型的空元素?

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

Good Afternoon.

I have been working with Oracle Advanced Queues to create a messaging system that we can use to determine when new lines are passed into the databse, when updates occur and when deletes occur.

I am using a single consumer queue and using correlations to control what data is looked for at certain times and my payload is of xmltype.

To generate the xml, I originally was using an xmlsequence to generate the message as below.

<MESSAGE>
<LOCATIONS>
  <LOCATION_ID>9999</LOCATION_ID>
  <LOC_TYPE>S</LOC_TYPE>
  <NAME>Test Location</NAME>
  <RETAILER_UNIT_CODE>T&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>

However, it has come to my attention that xmlsequence leaves out null elements, which is not ideal, as when it comes time for the messages to be picked up at the other end, they cannot be mapped on data field easily.
To try and work around this, I have tried to employ the use of DBMS_XMLGEN within my trigger, as it allows the handling of nulls in exactly the way I would want it handled.

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

The problem with this approach is that it will generate an exception, as it is trying to operate on the same table that the trigger has been executed from.

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

So I moved on to trying to use the new and old objects to get the data out and place it in to the context, but I am running in to a few hiccups with the values that are null, as they are playing havoc with my concatenating them in to the query string.

...
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;

So my question is: How can I go about solving this so that I can see my empty elements for my xml type?

I'm also open to suggestions along the way on how to solve it and will be checking back for any clarification requests.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

眼睛会笑 2024-10-15 17:00:11

要在 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>

to generate a simple row in XML you can use 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>
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文