extract value present between XML tags from a blob in Oracle SQL

南楼画角 提交于 2019-12-11 13:31:19

问题


these data is present in a blob COLUMN ("MSG") in my ADMINTXNUNAUTHDATA table

<PayBillerRequestDTO><idCustomer>00000024</idCustomer><idBiller>VODA</idBiller><billerName>ojas yadnik </billerName><billReferenceNumber>111</billReferenceNumber></PayBillerRequestDTO>

I want to show "111" present between <billReferenceNumber>111</billReferenceNumber>

and some other values coming from different tables in a single query

select mbl.idbiller as BILLNUMBER,
       mbl.billernickname AS BILLERNICKNAME,
       mts.idchanneluser AS USERNAME,
       adm.NUMAMOUNT AS AMOUNT,
       adm.ACCOUNTNO AS ACCOUNTNUM,
       adm.DATINITIATION AS TRANSACTIONDATE,
       adm.codcurr as CURRENCY
  from mstbiller mbl, ADMINTXNUNAUTHDATA adm, mstchanneluser mts
 where MTS.IDCHANNELUSER = '??'
   and adm.idinitiator = mts.iduser 
   and adm.txnid = 'BPA'
   and mbl.idbiller ='?'
   AND dbms_lob.instr(MSG, utl_raw.CAST_TO_RAW('<idBiller>?</idBiller>'), 1, 1) > 0;

回答1:


I would not recommend searching for XML tags with INSTR as it is space sensitive, for instance, it wouldn't find <idBiller>111</idBiller > or <idBiller a="x">111</idBiller>. It is XML after all, which is supposedly easy to parse. (Nobody mentioned the awfull syntax, though).

Secondly, BLOB is totally the wrong datatype. It is for binary data. Just wait for the first customer called Agüero or Jørgensen. The appropriate datatype for XML in Oracle is XMLTYPE:

CREATE TABLE admintxnunauthdata (
  accountno NUMBER,
  msg XMLTYPE
) XMLTYPE COLUMN msg STORE AS SECUREFILE BINARY XML (COMPRESS HIGH);

INSERT INTO admintxnunauthdata (accountno, msg) VALUES (1,
 '<PayBillerRequestDTO><idCustomer>00000024</idCustomer><idBiller>VODA</idBiller><billerName>ojas yadnik </billerName><billReferenceNumber>111</billReferenceNumber></PayBillerRequestDTO>');
INSERT INTO admintxnunauthdata (accountno, msg) VALUES (2,
 '<PayBillerRequestDTO><idCustomer>00000025</idCustomer><idBiller>JODA</idBiller><billerName>ojas yadnik </billerName><billReferenceNumber>222</billReferenceNumber></PayBillerRequestDTO>');

You can then search records by idBiller:

SELECT * 
  FROM admintxnunauthdata
 WHERE XMLExists('/PayBillerRequestDTO[idBiller="VODA"]' PASSING msg);

and extract tag values from the XML:

SELECT accountno,
       XMLQuery('/PayBillerRequestDTO/billReferenceNumber/text()' 
         PASSING msg RETURNING CONTENT)
  FROM admintxnunauthdata
 WHERE XMLExists('/PayBillerRequestDTO[idBiller="VODA"]' PASSING msg);

To convert the XML text to a normal datatype, use

SELECT accountno,
       XMLCast(XMLQuery('/PayBillerRequestDTO/billReferenceNumber/text()' 
         PASSING msg RETURNING CONTENT) AS NUMBER) AS billreferencenumber
  FROM admintxnunauthdata
 WHERE XMLExists('/PayBillerRequestDTO[idBiller="VODA"]' PASSING msg);

ACCOUNTNO BILLREFERENCENUMBER
        1                 111

If you cannot change (or let change) the table structure, you could in theory convert the BLOB to XMLTYPE on the fly, but I have no idea about the performance impact:

SELECT accountno,
       XMLCast(XMLQuery('/PayBillerRequestDTO/billReferenceNumber/text()' 
         PASSING msg RETURNING CONTENT) AS NUMBER) AS billreferencenumber
  FROM (
        SELECT accountno, XMLTYPE(msg,1) as msg 
          FROM admintxnunauthdata
       )
 WHERE XMLExists('/PayBillerRequestDTO[idBiller="VODA"]' PASSING msg);

For the conversion from BLOB to XMLTYPE, see convert oracle blob to xml type




回答2:


Xmltype constructor is overridden. One version is xmltype(blob,csid), blob is blob, csid is character set ID number corresponding to character set name. For utf8 it is 871.

Check example. First part is only to prepare blob value. In 2nd part i'm converting blob to xml using csid and i'm extracting data from xml using xmltable.

    create table blob_xml (a blob);

    declare 
      cisd number;
      myblob blob;
    begin 
-- save xml as blob
        SELECT NLS_CHARSET_ID('UTF8') into cisd FROM DUAL; 
        myblob := xmltype('<PayBillerRequestDTO><idCustomer>00000024</idCustomer><idBiller>VODA</idBiller><billerName>ojas yadnik </billerName><billReferenceNumber>111</billReferenceNumber></PayBillerRequestDTO>').getblobVal(cisd); 
       insert into blob_xml values(myblob);
       commit;
    end; 


        select * from blob_xml,xmltable('PayBillerRequestDTO' passing xmltype(a,871)
      columns idCustomer varchar2(4000) path 'idCustomer'
      ,idBiller varchar2(4000) path 'idBiller'
      ,billerName  varchar2(4000) path 'billerName'
      ,billReferenceNumber varchar2(4000) path 'billReferenceNumber'
      --etc
       )

;

I'm assuming that your xml is encoded with utf8




回答3:


You can use SUBSTRING_INDEX to do this:

Sample:

MariaDB [(none)]> SET @x:="<PayBillerRequestDTO><idCustomer>00000024</idCustomer><idBiller>VODA</idBiller><billerName>ojas yadnik </billerName><billReferenceNumber>111</billReferenceNumber></PayBillerRequestDTO>";
Query OK, 0 rows affected (0.00 sec)

MariaDB [(none)]> SELECT SUBSTRING_INDEX( SUBSTRING_INDEX( @x, "<billReferenceNumber>", -1), '</billReferenceNumber>', 1) as result;
+--------+
| result |
+--------+
| 111    |
+--------+
1 row in set (0.00 sec)

MariaDB [(none)]>


来源:https://stackoverflow.com/questions/51208429/extract-value-present-between-xml-tags-from-a-blob-in-oracle-sql

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!