问题
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