SQL Oracle exctrac value from XML unordered Collection - sql

I have a clob with XML like this:
<Data>
<Email_List>
<Email>
<EmailPrimaryFlag>Y</EmailPrimaryFlag>
<EmailAddress>test#test.it</EmailAddress>
</Email>
<Email>
<EmailPrimaryFlag>N</EmailPrimaryFlag>
<EmailAddress>test2#test2.it</EmailAddress>
</Email>
<Email>
<EmailPrimaryFlag>N</EmailPrimaryFlag>
<EmailAddress>test3#test3.it</EmailAddress>
</Email>
</Email_List>
<User>Name_User</User>
<City>City_test</City>
</Data>
I need to do an extract only for PrimaryFlag=Y
Usually i do something like this:
select
extract(xmltype(PAYLOAD),'//*:User/text()').getStringVal() as User,
extract(xmltype(PAYLOAD),'//*:City/text()').getStringVal() as City,
but i don't know how i can extract for mail with PrimaryFlag=Y
Special Thanks
Michel

Avoid using EXRACT() as it is deprecated.
with t (payload) as (
select to_clob('<Data>
<Email_List>
<Email>
<EmailPrimaryFlag>Y</EmailPrimaryFlag>
<EmailAddress>test#test.it</EmailAddress>
</Email>
<Email>
<EmailPrimaryFlag>N</EmailPrimaryFlag>
<EmailAddress>test2#test2.it</EmailAddress>
</Email>
<Email>
<EmailPrimaryFlag>N</EmailPrimaryFlag>
<EmailAddress>test3#test3.it</EmailAddress>
</Email>
</Email_List>
<User>Name_User</User>
<City>City_test</City>
</Data>') from dual)
select x.* from t, xmltable(
'/Data'
passing xmltype(payload)
columns
primary_email varchar2(60) path 'Email_List/Email/EmailAddress[../EmailPrimaryFlag = "Y"]',
username varchar2(60) path 'User',
city varchar2(60) path 'City'
)x;
PRIMARY_EMAIL USERNAME CITY
------------------------------------------------------------ ------------------------------------------------------------ ------------------------------------------------------------
test#test.it Name_User City_test

Related

Parsing XML with XMLTable n Oracle

I have one xml which holds customer and order details. I am parsing it using XMLTable. I think I am giving the correct XPath but I am getting no output.
Here is what I have tried. Hoping for assistance.
**DECLARE
l_raw_xml CLOB:= '<?xml version="1.0" encoding="utf-8"?>
<Root
xmlns="http://www.adventure-works.com">
<Customers>
<Customer CustomerID="GREAL">
<CompanyName>Great Lakes Food Market</CompanyName>
<ContactName>Howard Snyder</ContactName>
<ContactTitle>Marketing Manager</ContactTitle>
<Phone>(503) 555-7555</Phone>
<FullAddress>
<Address>2732 Baker Blvd.</Address>
<City>Eugene</City>
<Region>OR</Region>
<PostalCode>97403</PostalCode>
<Country>USA</Country>
</FullAddress>
</Customer>
</Customers>
<Orders>
<Order>
<CustomerID>LETSS</CustomerID>
<EmployeeID>6</EmployeeID>
<OrderDate>1997-11-10T00:00:00</OrderDate>
<RequiredDate>1997-12-08T00:00:00</RequiredDate>
<ShipInfo ShippedDate="1997-11-21T00:00:00">
<ShipVia>2</ShipVia>
<Freight>45.97</Freight>
<ShipName>Let Stop N Shop</ShipName>
<ShipAddress>87 Polk St. Suite 5</ShipAddress>
<ShipCity>San Francisco</ShipCity>
<ShipRegion>CA</ShipRegion>
<ShipPostalCode>94117</ShipPostalCode>
<ShipCountry>USA</ShipCountry>
</ShipInfo>
</Order>
</Orders>
</Root>';
l_xml_type XMLTYPE:=XMLTYPE.createXML(l_raw_xml);
cursor c_make_xml_object
is
SELECT x.*,
y.*
FROM XMLTABLE('/Root/Customers/Customer'
PASSING l_xml_type
COLUMNS
CustomerID VARCHAR2(255) PATH '#CustomerID',
CompanyName VARCHAR2(255) PATH 'CompanyName',
FullAddress XMLTYPE PATH 'FullAddress') x,
XMLTABLE('/FullAddress'
PASSING x.FullAddress
COLUMNS
Address VARCHAR2(255) PATH 'Address',
City VARCHAR2(255) PATH 'City') y ;
BEGIN
FOR rec IN c_make_xml_object
loop
DBMS_OUTPUT.PUT_LINE(rec.CustomerID);
DBMS_OUTPUT.PUT_LINE(rec.CompanyName);
END LOOP;
END;
/**
Do I have to account for the namespace? I had added namespace code but it did not work/
Change to this to include a default namespace:
FROM XMLTABLE(xmlnamespaces(default 'http://www.adventure-works.com'),
'/Root/Customers/Customer' ....
....
XMLTABLE(xmlnamespaces(default 'http://www.adventure-works.com'), '/FullAddress'
.....
Yes, a proper namespace definition is needed within the SQL query such as below :
SELECT x.*, y.*
FROM XML_TAB t,
XMLTABLE(XMLnamespaces('http://www.adventure-works.com' as "ns"),
'ns:Root/ns:Customers/ns:Customer'
PASSING t.xml_data
COLUMNS
CustomerID VARCHAR2(255) PATH '#CustomerID',
CompanyName VARCHAR2(255) PATH 'ns:CompanyName',
FullAddress XMLTYPE PATH 'ns:FullAddress'
) x,
XMLTABLE(XMLnamespaces('http://www.adventure-works.com' as "ns"),
'ns:FullAddress'
PASSING x.FullAddress
COLUMNS
Address VARCHAR2(255) PATH 'ns:Address',
City VARCHAR2(255) PATH 'ns:City') y ;
Demo with SQL
Demo with PL/SQL

Delete Empty tag from xmltype oracle

i want try to delete the empty tag from xmltype. I Have generate the below xml from oracle type. In the collection few elements does not have values so i generated with empty tag.
Can any one please help me out:
Actual output:
<MESSAGE>
<LOCATIONS>
<LOCATION_ID>9999</LOCATION_ID>
<LOC_TYPE>S</LOC_TYPE>
<NAME>Test Location</NAME>
<PHONE_NUM>08 </PHONE_NUM>
<LAST_MODIFIED_BY/>
<LAST_MODIFIED_DATE/>
<POS_CODE/>
</LOCATIONS>
</MESSAGE>
Expected output:
<MESSAGE>
<LOCATIONS>
<LOCATION_ID>9999</LOCATION_ID>
<LOC_TYPE>S</LOC_TYPE>
<NAME>Test Location</NAME>
<PHONE_NUM>08 </PHONE_NUM>
</LOCATIONS>
</MESSAGE>
Use DELETEXML and look for the XPath //*[not(text())][not(*)] to find elements that contain no text and no children:
SQL Fiddle
Oracle 11g R2 Schema Setup:
CREATE TABLE table_name ( xml ) AS
SELECT XMLTYPE( '<MESSAGE>
<LOCATIONS>
<LOCATION_ID>9999</LOCATION_ID>
<LOC_TYPE>S</LOC_TYPE>
<NAME>Test Location</NAME>
<PHONE_NUM>08 </PHONE_NUM>
<LAST_MODIFIED_BY/>
<LAST_MODIFIED_DATE/>
<POS_CODE/>
</LOCATIONS>
</MESSAGE>' ) FROM DUAL;
Query 1:
SELECT DELETEXML(
xml,
'//*[not(text())][not(*)]'
).getStringVal()
FROM table_name
Results:
| DELETEXML(XML,'//*[NOT(TEXT())][NOT(*)]').GETSTRINGVAL() |
|-----------------------------------------------------------------------------------------------------------------------------------------------------|
| <MESSAGE><LOCATIONS><LOCATION_ID>9999</LOCATION_ID><LOC_TYPE>S</LOC_TYPE><NAME>Test Location</NAME><PHONE_NUM>08 </PHONE_NUM></LOCATIONS></MESSAGE> |
SELECT
deletexml(xml_data, '//*[not(text())][not(*)]').getstringval()
FROM
(
SELECT
xmltype('<MESSAGE>
<LOCATIONS>
<LOCATION_ID>9999</LOCATION_ID>
<LOC_TYPE>S</LOC_TYPE>
<NAME>Test Location</NAME>
<PHONE_NUM>08 </PHONE_NUM>
<LAST_MODIFIED_BY/>
<LAST_MODIFIED_DATE/>
<POS_CODE/>
</LOCATIONS>
</MESSAGE>'
) xml_data
FROM
dual
)
this is working fine thanks

import xml to oracle database table

I have this sample xml my requirement is to parse it and fetch values from it's various nodes and insert them into one of oracle table.
<?xml version="1.0" encoding="UTF-8"?>
<Reporting>
<Selection>69</Selection>
<MonthEndDate>9/30/2016</MonthEndDate>
<Email>
<Name>abc</Name>
<Address>abc#gmail.com</Address>
</Email>
<Request>
<Port_id_list>
<Port_id>1901</Port_id>
<Port_id>1902</Port_id>
<Port_id>1903</Port_id>
</Port_id_list>
</Request>
</Reporting>
How can we do this?
Please help.
EDITED
For example:
WITH my_data AS
(SELECT xmltype('<?xml version="1.0" encoding="UTF-8"?>
<Reporting>
<Selection>69</Selection>
<MonthEndDate>9/30/2016</MonthEndDate>
<Email>
<Name>abc</Name>
<Address>abc#gmail.com</Address>
</Email>
<Request>
<Port_id_list>
<Port_id>1901</Port_id>
<Port_id>1902</Port_id>
<Port_id>1903</Port_id>
</Port_id_list>
</Request>
</Reporting>') my_xml
FROM dual)
SELECT extractValue(md.my_xml, 'Reporting/Selection/text()') selection_id,
extractValue(value(port_ids), 'Port_id/text()') port_id
FROM my_data md,
TABLE(XMLSequence (md.my_xml.extract ('Reporting/Request/Port_id_list/Port_id'))) port_ids;
If your XML has node with children create one-to-many with TABLE and XMLSequence.
You should preferably use XMLTABLE as the extractValue was deprecated
Here an example selecting teh ports with the (denormalized) parten attributes.
I added also posr sequence to preserve order of the ports.
WITH t AS
(SELECT xmltype('<?xml version="1.0" encoding="UTF-8"?>
<Reporting>
<Selection>69</Selection>
<MonthEndDate>9/30/2016</MonthEndDate>
<Email>
<Name>abc</Name>
<Address>abc#gmail.com</Address>
</Email>
<Request>
<Port_id_list>
<Port_id>1901</Port_id>
<Port_id>1902</Port_id>
<Port_id>1903</Port_id>
</Port_id_list>
</Request>
</Reporting>') xml
FROM dual)
select
x.Selection,x.MonthEndDate,x.emailName, x.emailAddress,
o.port_seq, o.port_id
from t,
XMLTable(
'for $i in /Reporting
return $i'
passing t.xml
columns
Selection varchar2(30) path 'Selection',
MonthEndDate varchar2(30) path 'MonthEndDate',
emailName varchar2(30) path 'Email/Name',
emailAddress varchar2(30) path 'Email/Address',
Port_id_list XMLType path '//Port_id'
) x,
XMLTable(
'./Port_id'
passing (x.Port_id_list)
columns
port_seq for ordinality,
port_id varchar2(30) path '/Port_id'
) o
;
SELECTION MONTHENDDATE EMAILNAME EMAILADDRESS PORT_SEQ PORT_ID
------------------------------ ------------------------------ ------------------------------ ------------------------------ ---------- ------------------------------
69 9/30/2016 abc abc#gmail.com 1 1901
69 9/30/2016 abc abc#gmail.com 2 1902
69 9/30/2016 abc abc#gmail.com 3 1903

convert XML to table in oracle

I have a XML in the below format, store in column of XMLType in oracle database
<a>
<c>1</c>
<c>2</c>
</a>
I need to convert this in table format as
c
1
2
Any idea how to do this using SQL?
with data as
(select '<a><c>1</c><c>2</c></a>' xmlval
from dual)
( select c
from data d,
xmltable('/a/*' passing xmltype(d.xmlval)
columns
c varchar2(254) path '/c'
))
There is answer in this url.
For instance user daggett did this:
select *
FROM XMLTABLE('/person/row'
PASSING
xmltype('
<person>
<row>
<name>Tom</name>
<Address>
<State>California</State>
<City>Los angeles</City>
</Address>
</row>
<row>
<name>Jim</name>
<Address>
<State>California</State>
<City>Los angeles</City>
</Address>
</row>
</person>
')
COLUMNS
--describe columns and path to them:
name varchar2(20) PATH './name',
state varchar2(20) PATH './Address/State',
city varchar2(20) PATH './Address/City'
) xmlt
;
Thanks, it's work.
pISLEMLER CLOB;
select *
FROM XMLTABLE('/mydata/UCRET'
PASSING
xmltype('<mydata>'||pISLEMLER||'</mydata>
')
COLUMNS
--describe columns and path to them:
F_M_IS_ID varchar2(20) PATH './FMISID',
ISKONTO varchar2(20) PATH 'ISK'
) xmlt;

SELECTing multiple values for the same attribute using FOR XML in SQL

I'm attempting to retrieve data from a SQL table as XML. Consider the following table:
Customers
Id Last First Phone1 Phone2
10 Doe John 555-2121 555-6145
33 Smith Sally 555-3333 555-7000
I'd like to retrieve the Last, First, Phone1, and Phone2 fields using the FOR XML clause in SQL. However, I'd like to retrieve the Phone2 field with an attribute of "Evening". For example, I'd like the XML to look like:
<Customers>
<Customer>
<Last>Doe</Last>
<First>John</First>
<Phone Type="Daytime">555-2121</Phone>
<Phone Type="Evening">555-6145</Phone>
</Customer>
</Customers>
However, I'm unable to get it to work. Is there something I'm missing? Any and all help would be greatly appreciated!
You can build the nodes in a subquery. If you specify for xml type, the subqueries merge with the outer query to give one XML:
select Last as [Last]
, First as [First]
, (
select 'Daytime' as [#Type]
, Phone1 as [*]
for xml path('Phone'), type
)
, (
select 'Evening' as [#Type]
, Phone2 as [*]
for xml path('Phone'), type
)
from Customers
for xml path('Customer'), root('Customers')
This prints:
<Customers>
<Customer>
<Last>Doe</Last>
<First>John</First>
<Phone Type="Daytime">555-2121</Phone>
<Phone Type="Evening">555-6145</Phone>
</Customer>
<Customer>
<Last>Smith</Last>
<First>Sally</First>
<Phone Type="Daytime">555-3333</Phone>
<Phone Type="Evening">555-7000</Phone>
</Customer>
</Customers>
Live example at SQL Fiddle.