Oracle, regexp_substr - how to match 'string'+regex - oracle

I have a column that gives me lines like this:
<?xml version="1.0" encoding="UTF-8"?>
<xSettings>
<systemPropertyName>BLALBLA</systemPropertyName>
<minimumAmount>198.00</minimumAmount>
<closingAmount>198.00</closingAmount>
<useThisSetting>true</useThisSetting>
<SystemStep dayAfterPrevious="0">
<System SystemService="1" minimumAmount="450.00" />
</SystemStep>
<SystemStep dayAfterPrevious="8">
<message />
</SystemStep>
<SystemStep dayAfterPrevious="3">
<block />
</SystemStep>
<SystemStep dayAfterPrevious="1">
<message />
</SystemStep>
<SystemStep dayAfterPrevious="7">
<message />
</SystemStep>
</xSettings>
All numbers in it are variable and the BLA BLA is variable too. What I want is a select that only gives me
<minimumAmount>198.00</minimumAmount>
though this would be eve better:
198.00
basically, I can't figure out how to use regexp_substr to find a specific string , then return a number just after that may be from 1 to 4 digits and has two decimals after.

Do not use regular expressions to parse XML data - use a proper XML parser:
SELECT x.minimumAmount
FROM your_table t,
XMLTable(
'/xSettings',
PASSING XMLType( t.your_column )
COLUMNS minimumAmount NUMBER(5,2) PATH './minimumAmount'
) x
Or
SELECT TO_NUMBER(
EXTRACTVALUE( XMLType( your_column ), '/xSettings/minimumAmount' )
) AS minimumAmount
FROM your_table

XML data should not be queried using regular expressions, but here:
select
regexp_substr(col, '<minimumAmount>(.*)</minimumAmount>',1,1,null,1) minimum_amount
from your_table;
One other way is to use regexp_replace like this:
select
regexp_replace(col, '.*<minimumAmount>(.*)</minimumAmount>.*','\1') minimum_amount
from your_table;

Related

XMLType Extract Unique ID from Single Cell

Can you please help me out to fix the following?
I only required a person_number once eg. 1000142 but I'm getting 10001421000142 like this.
Because the values I have in XML cell have repeating number, so I only want to extract one unique person number.
select xmltype('<?xml version="1.0"?>
<ROWSET>
<ROW0> <PERSON_NUMBER>1000142</PERSON_NUMBER> <LOAN_1>25000</LOAN_1> <LOAN_2>26000</LOAN_2>
</ROW0>
<ROW0> <PERSON_NUMBER>1000142</PERSON_NUMBER> </ROW0> <LOAN_1>25000</LOAN_1> <LOAN_2>26000</LOAN_2>
</ROW0>
</ROWSET>').extract( '//PERSON_NUMBER/text()' ).getstringval() p#
from dual;
Based on your initial version of the question (where the XML is a valid with a single root element rather than a forest of elements), you can use:
select xmltype(
'<?xml version="1.0"?>
<ROWSET>
<ROW>
<PERSON_NUMBER>1000142</PERSON_NUMBER>
<PERSON_NUMBER>1000142</PERSON_NUMBER>
<LOAN_1>25000</LOAN_1>
<LOAN_2>26000</LOAN_2>
</ROW>
</ROWSET>').extract( '//PERSON_NUMBER[1]/text()' ) .getstringval() p#
from dual;
Which outputs:
P#
1000142
db<>fiddle here

updating CLOB column with multiple namespace in Oracle

I am trying to update an element which is inside a clob column in oracle DB.
First challenge I am facing is that my clob xml has 2 namespaces and I am not able to get that working .
<?xml version="1.0"?>
<esbmsg:EsbMessage xmlns:esbmsg="http://www.test.com/esb/message/1.0">
<esbmsg:Body>
<Transaction xmlns="http://test.com">
<test-element>
<finalElement>false</finalElement>
</test-elemen>
</Transaction>
</esbmsg:Body>
</esbmsg:EsbMessage>
select x.* from cc_messagehistory y
cross join xmltable(
xmlnamespaces('http://www.test.com/esb/message/1.0' as "esbmsg",
'http://test.com ' ),
'/esbmsg:EsbMessage'
passing xmltype.createxml(y.payload)
factext varchar2(10) path '/esbmsg:EsbMessage/esbmsg:Body/Transaction/test-element/finalElement'
) x;
ORA-19102: XQuery string literal expected
19102. 00000 - "XQuery string literal expected"
*Cause: The string literal containing the XQuery expression was missing.
*Action: Specify the XQuery expression as a string literal. Error at Line: 64 Column: 99
The immediate cause of the ORA-01902 is that you missed the default keyword:
xmlnamespaces('http://www.test.com/esb/message/1.0' as "esbmsg",
default 'http://test.com'),
I've removed the extra space at the end of the URI, which would cause problems later. But you are also missing the columns keyword, and you can simplify the conversion of the CLOB value to an XMLType.
Putting that together, and with a CTE to supply your (corrected) sample XML:
-- CTE for sample data
with cc_messagehistory(payload) as (
select to_clob('<?xml version="1.0"?>
<esbmsg:EsbMessage xmlns:esbmsg="http://www.test.com/esb/message/1.0">
<esbmsg:Body>
<Transaction xmlns="http://test.com">
<test-element>
<finalElement>false</finalElement>
</test-element>
</Transaction>
</esbmsg:Body>
</esbmsg:EsbMessage>') from dual
)
-- actual query
select x.*
from cc_messagehistory y
cross join xmltable (
xmlnamespaces (
'http://www.test.com/esb/message/1.0' as "esbmsg",
default 'http://test.com'
),
'/esbmsg:EsbMessage'
passing xmltype(y.payload)
columns factext varchar2(10)
path '/esbmsg:EsbMessage/esbmsg:Body/Transaction/test-element/finalElement'
) x;
FACTEXT
----------
false
For the update you could do something like:
update cc_messagehistory y
set payload = XMLSerialize(document
XMLQuery('declare default element namespace "http://test.com"; (: :)
declare namespace esbmsg="http://www.test.com/esb/message/1.0"; (: :)
copy $i := $xml modify (
for $j in $i//esbmsg:EsbMessage/esbmsg:Body/Transaction/test-element/finalElement
return replace value of node $j with $new
)
return $i'
passing xmltype(y.payload) as "xml",
'true' AS "new"
returning content
)
indent size=2
)
where xmlexists('declare default element namespace "http://test.com"; (: :)
declare namespace esbmsg="http://www.test.com/esb/message/1.0"; (: :)
$xml//esbmsg:EsbMessage/esbmsg:Body/Transaction/test-element/finalElement[text()="false"]'
passing xmltype(y.payload) as "xml");
which transforms that source CLOB into:
<?xml version="1.0"?>
<esbmsg:EsbMessage xmlns:esbmsg="http://www.test.com/esb/message/1.0">
<esbmsg:Body>
<Transaction xmlns="http://test.com">
<test-element>
<finalElement>true</finalElement>
</test-element>
</Transaction>
</esbmsg:Body>
</esbmsg:EsbMessage>
db<>fiddle (works on 18c; errors on 11gR2, but patch levels may make a difference; also tested successfully elsewhere on 12cR1)

read the XML type column using stored procedure

How to display parent tags and attributes from XML TYPE column using stored procedure?
Example: I have below data in XMLTYPE Column in one table:
<Employee>
<Employee_information >
<Employee_content>
<task>
<Employee_stem>
<Employee_stem_paragraph>fsdbnfjksdflsdj.</Employee_stem_paragraph>
<Employee_stem_paragraph>dsfsdfsdfsdf</Employee_stem_paragraph>
</Employee_stem>
<Employee_response>
<Employee_response_choices>
<Employee_choice_list>
<Employee_block_choice numeric_identifier="1">
<Employee_choice_paragraph>sdfsdfsdfsdf</Employee_choice_paragraph>
</Employee_block_choice>
</Employee_choice_list>
</Employee_response_choices>
</Employee>
Output: display all the parent tags and attributes in it.
Output example:
Employee,Employee_information,Employee_content,Employee_stem,Employee_stem_paragraph,Employee_response,Employee_response_choices,Employee_choice_list,Employee_block_choice,
numeric_identifier,Employee_choice_paragraph.
In general you have to fix you xml. All tag have to be closed.
1-st select //*/name(.) - extract only element's name.
2-en select '//*/name(#*) -extract only attributes' name.
select *
from xmltable('//*/name(.)'
passing xmltype('<Employee>
<Employee_information>
<Employee_content>
<task>
<Employee_stem>
<Employee_stem_paragraph>fsdbnfjksdflsdj.</Employee_stem_paragraph>
<Employee_stem_paragraph>dsfsdfsdfsdf</Employee_stem_paragraph>
</Employee_stem>
<Employee_response>
<Employee_response_choices>
<Employee_choice_list>
<Employee_block_choice numeric_identifier="1">
<Employee_choice_paragraph>sdfsdfsdfsdf</Employee_choice_paragraph>
</Employee_block_choice>
</Employee_choice_list>
</Employee_response_choices>
</Employee_response>
</task>
</Employee_content>
</Employee_information>
</Employee>') columns name varchar2(200) path '.' )
union all
select *
from xmltable('//*/name(#*)'
passing xmltype('<Employee>
<Employee_information>
<Employee_content>
<task>
<Employee_stem>
<Employee_stem_paragraph>fsdbnfjksdflsdj.</Employee_stem_paragraph>
<Employee_stem_paragraph>dsfsdfsdfsdf</Employee_stem_paragraph>
</Employee_stem>
<Employee_response>
<Employee_response_choices>
<Employee_choice_list>
<Employee_block_choice numeric_identifier="1">
<Employee_choice_paragraph>sdfsdfsdfsdf</Employee_choice_paragraph>
</Employee_block_choice>
</Employee_choice_list>
</Employee_response_choices>
</Employee_response>
</task>
</Employee_content>
</Employee_information>
</Employee>') columns name varchar2(200) path '.' )

oracle xmltable performace - converting clob to xmltype and extracting for multiple records

I have a specific issue. i am trying to retrieve values from a xml clob field in a column. this xml is very large and i have of over 40 thousand records that have this xml_clob. I am currently able to retrieve information using the displayed query but found that performance is a big issue. Currently, its take hours to process the query. i need to be able to reduce this query processing time just a few minutes. There is not xml_schema provided. Access to the server is very limited so i can can create is temporary Table. But this has not been much help. These follow query only displays "Gender". It takes minimum of 15 minutes.
example of xml
<root>
<entry>....</entry>
<entry effective="2010012108354553" timestamp="2010012108354553" id="12345">
<field name="Org" t="0" s="4" d="0">
<nv>0000</nv>
</field>
<field name="FirstName" t="1" s="13" d="0">
<nv>John</nv>
</field>
<field name="LastName" t="1" s="13" d="0">
<nv>Doe</nv>
</field>
<entry>
</root>
query:
SELECT X.*,X2.*
From XML_TABLE XM,
XMLTABLE (
'for $e in /entry
where $e/#type = "create"
and $e/#effective > 20110229
and $e/#effective < 20140229
return $e'
passing extract(xml, '/root/entry')
COLUMNS
effective VARCHAR(60) PATH '/entry/#effective'
) AS X ,
XMLTABLE (
'for $i in /field
where $i/#name = "Gender"
return $i'
passing X.xml
COLUMNS
name VARCHAR(60) PATH '/field/#name',
old_value VARCHAR(60) PATH '/field/ov',
new_value VARCHAR(60) PATH '/field/nv'
) AS X2

How to correctly print xml data from clob?

For example, my clob contains xml content as shown below
<?xml version="1.0"?>
<content>
<foo>bar</foo>
<bar>foo</bar>
</content>
When i print it using loop, struct of content is not well-formed.
Use XMLSerialize function:
with test_data as (
select
'<?xml version="1.0"?><content>
<foo>bar</foo><bar>foo</bar></content>' as x_data
from dual
)
select
xmlserialize(document xmltype(x_data) as clob indent size = 2) x_text
from test_data
SQLFiddle

Resources