How to return multiple results with XMLTABLE? - oracle

I want to do a query in Oracle using xmltable.
Everything works fine, but there are multiple (n) results for xml node "article_title". For each row the result "<string>Article Name1</string><string>Article Name 2</string>... is returned. But I want every article name to be returned as a single row.
How can I realize this?
SELECT
X.*
FROM
myTable C,
xmltable (
'$cust//member' PASSING C.STAT_XML as "cust"
COLUMNS
name VARCHAR(25) PATH '/member/name',
article_title XMLTYPE PATH '//string/text()'
) as X
WHERE X.name = 'articles';

I'm having a problem with this as well. I have an XML that's supposed to send shipment data from our warehouse management system back to our order management system, and it has various different things that have multiples. The entire XML message has a single ShipConfirmHeader section, so that's easy enough to pull out. Where I run into trouble is that it has a ShipConfirmDetail/Orders section, and there could be any number of orders listed. Within each order, there could be any number of order lines. I can pull the ShipConfirmHeader and the ShipConfirmDetail/Orders together OR I can pull the ShipConfirmHeader and the ShipConfirmDetail/Orders/OrderLineItem together, but when I try pulling the Orders together with the OrderLineItem, there's no way that I can see to join those, so I end up with a cartesian product. To complicate matters even more, each Order could have many Cartons associated with it, and each Carton could contain multiple OrderLineItems, and each Carton could have multiple CartonDetails.
I've included a sample of my XML below. In this example, there's only one Order, one OrderLine, and one Carton (called an LPN in the XML), because I've stripped out all the others (the original XML is over 4000 lines long).
Pulling stuff from the ShipConfirmHeader is relatively easy, like this:
xmltable('/tXML/Message/ShipConfirm/ShipConfirmSummary/ShipConfirmHeaderInfo/'
passing xmltype(msg_xml.full_xml)
columns
invoice_batch varchar2(20) path 'InvcBatchNbr'
) sc_hdr
But when I want to include any of the multiples, it gives me problems. I've tried a variety of things:
-- This gives the error "ORA-22950: cannot ORDER objects without MAP or ORDER method"
xmltable('/tXML/Message/ShipConfirm'
passing xmltype(msg_xml.full_xml)
columns
invoice_batch varchar2(20) path 'ShipConfirmSummary/ShipConfirmHeaderInfo/InvcBatchNbr',
order_dtl xmltype path 'ShipConfirmDetails/Orders'
) sc_hdr
-- This doesn't like the "../" in the XPATH
xmltable('/tXML/Message/ShipConfirm/ShipConfirmDetails/Orders/OrderLineItem'
passing xmltype(msg_xml.full_xml)
columns
invoice_batch varchar2(20) path '../../../ShipConfirmSummary/ShipConfirmHeaderInfo/InvcBatchNbr',
order_id varchar2(20) path '../TcOrderId',
order_line_id varchar2(20) path 'TcOrderLineId',
item_name varchar2(20) path 'ItemName'
) sc_hdr
-- This gives a cartesian product.
xmltable('/tXML/Message/ShipConfirm/ShipConfirmSummary/ShipConfirmHeaderInfo'
passing xmltype(msg_xml.full_xml)
columns
invoice_batch varchar2(20) path 'InvcBatchNbr'
) sc_hdr,
xmltable('/tXML/Message/ShipConfirm/ShipConfirmDetails/Orders'
passing xmltype(msg_xml.full_xml)
columns
order_id varchar2(20) path 'TcOrderId'
) sc_ord_hdr,
xmltable('/tXML/Message/ShipConfirm/ShipConfirmDetails/Orders/OrderLineItem'
passing xmltype(msg_xml.full_xml)
columns
order_line_id varchar2(20) path 'TcOrderLineId',
item_name varchar2(20) path 'ItemName'
) sc_ord_dtl
Here's the sample XML:
<?xml version="1.0" encoding="UTF-8"?>
<tXML>
<Header>
<Source>warehouse management system</Source>
<Action_Type></Action_Type>
<Sequence_Number></Sequence_Number>
<Batch_ID></Batch_ID>
<Reference_ID></Reference_ID>
<User_ID>CRONUSER</User_ID>
<Password></Password>
<Message_Type>ShipConfirm</Message_Type>
<Company_ID>1</Company_ID>
<Msg_Locale>English (United States)</Msg_Locale>
<Msg_Time_Zone>America/Denver</Msg_Time_Zone>
<Version>2018</Version>
</Header>
<Message>
<ShipConfirm>
<ShipConfirmSummary>
<CompanyName>Blah</CompanyName>
<FacilityName>Blah</FacilityName>
<ShipConfirmHeaderInfo>
<InvcBatchNbr>123456</InvcBatchNbr>
<LastInvcDttm>5/27/21 05:45</LastInvcDttm>
<ShippedDttm>5/27/21 05:45</ShippedDttm>
<DateCreated>5/27/21 05:45</DateCreated>
<StoreNbr></StoreNbr>
<ShipVia>ST</ShipVia>
<SchedDeliveryDate></SchedDeliveryDate>
<ProNbr></ProNbr>
<AppointmentNbr></AppointmentNbr>
<ManifestNbr></ManifestNbr>
<SealNbr></SealNbr>
<AppointmentDate></AppointmentDate>
<PartialShipConfirmStatus>5</PartialShipConfirmStatus>
<PreBillStatus>0</PreBillStatus>
<ApptMadeByID></ApptMadeByID>
<BillOfLading></BillOfLading>
<CancelQuantity>0.0</CancelQuantity>
<NbrOfLpns>26</NbrOfLpns>
<NbrOfPlts>0</NbrOfPlts>
<NbrOfOrders>26</NbrOfOrders>
<TotalWt>61.72</TotalWt>
<UserID>USER</UserID>
</ShipConfirmHeaderInfo>
</ShipConfirmSummary>
<ShipConfirmDetails>
<Orders>
<BatchCtrlNbr>123456</BatchCtrlNbr>
<DistributionShipVia>ST</DistributionShipVia>
<DoType>Customer Order</DoType>
<DsgShipVia>ST</DsgShipVia>
<OriginalShipVia>ST</OriginalShipVia>
<IncotermLocAvaTimeZoneId>America/New_York</IncotermLocAvaTimeZoneId>
<InvcBatchNbr>123456</InvcBatchNbr>
<IsBackOrdered>1</IsBackOrdered>
<MajorOrderCtrlNbr></MajorOrderCtrlNbr>
<OrderType>ECOMM_ORDER</OrderType>
<ShipDate>5/27/21 05:45</ShipDate>
<OrderStatus>Unplanned</OrderStatus>
<DoStatus>Shipped</DoStatus>
<TcCompanyId>1</TcCompanyId>
<TcOrderId>MYORDERID</TcOrderId>
<TotalNbrOfLpn>1</TotalNbrOfLpn>
<TotalNbrOfPlt>0</TotalNbrOfPlt>
<TotalNbrOfUnits>1</TotalNbrOfUnits>
<LineHaulShipVia>ST</LineHaulShipVia>
<PartialShipConfirmStatus>5</PartialShipConfirmStatus>
<PreBillStatus>0</PreBillStatus>
<OrderBillToInfo>
<BillToAddress1>Snip</BillToAddress1>
<BillToAddress2></BillToAddress2>
<BillToAddress3></BillToAddress3>
<BillToCity>Snip</BillToCity>
<BillToContact></BillToContact>
<BillToContactName></BillToContactName>
<BillToCountryCode>CA</BillToCountryCode>
<BillToCounty></BillToCounty>
<BillToFacilityName></BillToFacilityName>
<BillToName>Snip</BillToName>
<BillToPhoneNumber>Snip</BillToPhoneNumber>
<BillToPostalCode>Snip</BillToPostalCode>
<BillToStateProv>ON</BillToStateProv>
</OrderBillToInfo>
<OrderDestInfo>
<DestAddress1>Snip</DestAddress1>
<DestAddress2></DestAddress2>
<DestAddress3></DestAddress3>
<DestCity>Snip</DestCity>
<DestContact>Snip</DestContact>
<DestCountryCode>CA</DestCountryCode>
<DestCounty></DestCounty>
<DestDockDoorId>0</DestDockDoorId>
<DestFacilityAliasId></DestFacilityAliasId>
<DestFacilityId>0</DestFacilityId>
<DestFacilityName></DestFacilityName>
<DestName>Snip</DestName>
<DestPhoneNumber>Snip</DestPhoneNumber>
<DestPostalCode>Snip</DestPostalCode>
<DestStateProv>ON</DestStateProv>
</OrderDestInfo>
<OrderOriginInfo>
<OriginAddress1>Snip</OriginAddress1>
<OriginAddress2></OriginAddress2>
<OriginAddress3></OriginAddress3>
<OriginCity>Snip</OriginCity>
<OriginContact></OriginContact>
<OriginCountryCode>CA</OriginCountryCode>
<OriginFacilityAliasId>Snip</OriginFacilityAliasId>
<OriginFacilityId>1</OriginFacilityId>
<OriginFacilityName>Snip</OriginFacilityName>
<OriginPhoneNumber></OriginPhoneNumber>
<OriginPostalCode>Snip</OriginPostalCode>
<OriginStateProv>AB</OriginStateProv>
</OrderOriginInfo>
<OrderInfoFields>
<SplInstrCode1>MW</SplInstrCode1>
<SplInstrCode2>MW</SplInstrCode2>
</OrderInfoFields>
<OrderLineItem>
<InvcBatchNbr>123456</InvcBatchNbr>
<ItemId>159331</ItemId>
<ItemName>MYITEMNAME</ItemName>
<LineItemId>12053970</LineItemId>
<OrderQty>1</OrderQty>
<OrderQtyUom>Unit</OrderQtyUom>
<OrigItemId>159331</OrigItemId>
<OrigItemName>MYITEMNAME</OrigItemName>
<OrigOrderLineItemId>1</OrigOrderLineItemId>
<OrigOrderQty>1</OrigOrderQty>
<OrigOrderQtyUom>Unit</OrigOrderQtyUom>
<OutptOrderLineItemId>3782033</OutptOrderLineItemId>
<Price>15.39</Price>
<PriceTktType></PriceTktType>
<RetailPrice>0.0</RetailPrice>
<ShippedQty>1</ShippedQty>
<TcCompanyId>1</TcCompanyId>
<TcOrderLineId>1</TcOrderLineId>
<UnitVol>0.0744</UnitVol>
<UnitWt>0.58</UnitWt>
<Uom>Unit</Uom>
<UserCanceledQty>0</UserCanceledQty>
<OrderLineItemDefn>
<ItemStyle>Snip</ItemStyle>
<ItemStyleSfx>Snip</ItemStyleSfx>
</OrderLineItemDefn>
</OrderLineItem>
<Lpn>
<BillOfLadingNumber></BillOfLadingNumber>
<CFacilityAliasId>Snip</CFacilityAliasId>
<EstimatedWeight>0.58</EstimatedWeight>
<FinalDestFacilityAliasId></FinalDestFacilityAliasId>
<InvcBatchNbr>123456</InvcBatchNbr>
<LoadedDttm></LoadedDttm>
<ManifestNbr></ManifestNbr>
<MasterBolNbr></MasterBolNbr>
<NonInventoryLpnFlag>0</NonInventoryLpnFlag>
<NonMachineable></NonMachineable>
<OutptLpnId>730888</OutptLpnId>
<PackerUserid>USER</PackerUserid>
<ProcDttm>5/27/21 05:45</ProcDttm>
<ProcStatCode>0</ProcStatCode>
<QtyUom>Unit</QtyUom>
<ServiceLevel></ServiceLevel>
<ShipVia>ST</ShipVia>
<ShippedDttm>5/27/21 05:45</ShippedDttm>
<StaticRouteId></StaticRouteId>
<TcCompanyId>1</TcCompanyId>
<TcLpnId>98765</TcLpnId>
<TcOrderId>Snip</TcOrderId>
<TcParentLpnId></TcParentLpnId>
<TcShipmentId></TcShipmentId>
<TotalLpnQty>1</TotalLpnQty>
<TrackingNbr>Snip</TrackingNbr>
<VolumeUom>cu ft</VolumeUom>
<Weight>0.58</Weight>
<WeightUom>Lbs</WeightUom>
<LoadSequence>0</LoadSequence>
<oLPNXRefNbr></oLPNXRefNbr>
<LpnDetail>
<InvcBatchNbr>123456</InvcBatchNbr>
<ItemId>159331</ItemId>
<ItemName>MYITEMNAME</ItemName>
<LpnDetailId>20153787</LpnDetailId>
<OutptLpnDetailId>3689518</OutptLpnDetailId>
<QtyUom>Unit</QtyUom>
<SizeValue>1</SizeValue>
<TcCompanyId>1</TcCompanyId>
<TcLpnId>98765</TcLpnId>
<DistroNumber></DistroNumber>
<TcOrderLineId>1</TcOrderLineId>
<MinorOrderNbr>Snip</MinorOrderNbr>
<MinorPoNbr></MinorPoNbr>
</LpnDetail>
</Lpn>
</Orders>
</ShipConfirmDetails>
</ShipConfirm>
</Message>
</tXML>

Try something like this:
SELECT X.*
FROM my_table C,
xmltable('for $i in $cust//string , $j in $cust//member[./string=$i]/name return <member>{$j}{$i}</member>'
passing c.stat_xml AS "cust"
columns name varchar2(25) path '/member/name',
article_title xmltype path '//string') AS X
WHERE X.name = 'articles';
Here is a fiddle
I assumed that for every member you have one name but might have many strings

Related

Accessing values in XML from a variable in Oracle SQL

I have a XML data as below in a variable p_val:
<env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:wsa="http://www.w3.org/2005/08/addressing">
<env:Header>
<wsa:MessageID>urn:bda29066-5961-11ec-87ec-0242c5d8b376</wsa:MessageID>
<wsa:ReplyTo>
<wsa:Address>http://www.w3.org/2005/08/addressing/anonymous</wsa:Address>
<wsa:ReferenceParameters>
<instra:tracking.ecid xmlns:instra="http://xmlns.oracle.com/sca/tracking/1.0">9b657011-42e4-4cf4-a78e-537551de4cc0-0057ca4a</instra:tracking.ecid>
<instra:tracking.FlowEventId xmlns:instra="http://xmlns.oracle.com/sca/tracking/1.0">27818206</instra:tracking.FlowEventId>
<instra:tracking.FlowId xmlns:instra="http://xmlns.oracle.com/sca/tracking/1.0">169007626</instra:tracking.FlowId>
<instra:tracking.CorrelationFlowId xmlns:instra="http://xmlns.oracle.com/sca/tracking/1.0">0000NqYCMWFDGfdLxeG7yW1X_Nsm0003Yk</instra:tracking.CorrelationFlowId>
<instra:tracking.quiescing.SCAEntityId xmlns:instra="http://xmlns.oracle.com/sca/tracking/1.0">1830036</instra:tracking.quiescing.SCAEntityId>
</wsa:ReferenceParameters>
</wsa:ReplyTo>
<wsa:FaultTo>
<wsa:Address>http://www.w3.org/2005/08/addressing/anonymous</wsa:Address>
</wsa:FaultTo>
</env:Header>
<env:Body>
<LaunchSpreadSheetWorkFlowResponse xmlns="http://xmlns.oracle.com/bpmn/bpmnCloudProcess/ISV_ROYALTIES/ISVSpreadSheetMainProcess">
<instanceNumber xmlns:def="http://www.w3.org/2001/XMLSchema" xsi:type="def:long"
xmlns=""
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">79630772</instanceNumber>
</LaunchSpreadSheetWorkFlowResponse>
</env:Body>
</env:Envelope>
I want to access the value of the tag: instanceNumber which is 79630772.
If it is a direct payload instead of a variable I tried accessing it using:
select *
FROM XMLTABLE('/Envelope/Body/LaunchSpreadSheetWorkFlowResponse'
PASSING
xmltype('
<env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:wsa="http://www.w3.org/2005/08/addressing">
<env:Header>
<wsa:MessageID>urn:bda29066-5961-11ec-87ec-0242c5d8b376</wsa:MessageID>
<wsa:ReplyTo>
<wsa:Address>http://www.w3.org/2005/08/addressing/anonymous</wsa:Address>
<wsa:ReferenceParameters>
<instra:tracking.ecid xmlns:instra="http://xmlns.oracle.com/sca/tracking/1.0">9b657011-42e4-4cf4-a78e-537551de4cc0-0057ca4a</instra:tracking.ecid>
<instra:tracking.FlowEventId xmlns:instra="http://xmlns.oracle.com/sca/tracking/1.0">27818206</instra:tracking.FlowEventId>
<instra:tracking.FlowId xmlns:instra="http://xmlns.oracle.com/sca/tracking/1.0">169007626</instra:tracking.FlowId>
<instra:tracking.CorrelationFlowId xmlns:instra="http://xmlns.oracle.com/sca/tracking/1.0">0000NqYCMWFDGfdLxeG7yW1X_Nsm0003Yk</instra:tracking.CorrelationFlowId>
<instra:tracking.quiescing.SCAEntityId xmlns:instra="http://xmlns.oracle.com/sca/tracking/1.0">1830036</instra:tracking.quiescing.SCAEntityId>
</wsa:ReferenceParameters>
</wsa:ReplyTo>
<wsa:FaultTo>
<wsa:Address>http://www.w3.org/2005/08/addressing/anonymous</wsa:Address>
</wsa:FaultTo>
</env:Header>
<env:Body>
<LaunchSpreadSheetWorkFlowResponse xmlns="http://xmlns.oracle.com/bpmn/bpmnCloudProcess/ISV_ROYALTIES/ISVSpreadSheetMainProcess">
<instanceNumber xmlns:def="http://www.w3.org/2001/XMLSchema" xsi:type="def:long"
xmlns=""
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">79630772</instanceNumber>
<name>XYZ</name>
</LaunchSpreadSheetWorkFlowResponse>
</env:Body>
</env:Envelope>
')
COLUMNS
temp2 varchar2(20) PATH './instanceNumber'
) xmlt
;
The above query returned an empty value.
How should I access the value from a variable?
You need to specify and supply the namespaces:
select *
FROM XMLTABLE(
XMLNAMESPACES(
default 'http://xmlns.oracle.com/bpmn/bpmnCloudProcess/ISV_ROYALTIES/ISVSpreadSheetMainProcess',
'http://schemas.xmlsoap.org/soap/envelope/' AS "env"
),
'/env:Envelope/env:Body/LaunchSpreadSheetWorkFlowResponse'
PASSING
...
COLUMNS
temp2 varchar2(20) PATH '*:instanceNumber'
) xmlt
;
The Envelope and Body come under the SOAP env namespace. In the XML document the LaunchSpreadSheetWorkFlowResponse node doesn't have a namespace prefix but defines a default namespace, so that default needs to be supplied too. Then it gets slightly awkward for instanceNumber as that node redefines (or clears) the default, and defines additional namespaces, but doesn't use them - which puts that node in limbo a bit. I've taken the easy route and wildcarded that with the *: prefix.
The less lazy way, I think, is to treat the LaunchSpreadSheetWorkFlowResponse as a separate XML fragment with a seconf XMLTable call:
select xmlt2.instanceNumber
FROM XMLTABLE(
XMLNAMESPACES(
default 'http://xmlns.oracle.com/bpmn/bpmnCloudProcess/ISV_ROYALTIES/ISVSpreadSheetMainProcess',
'http://schemas.xmlsoap.org/soap/envelope/' AS "env"
),
'/env:Envelope/env:Body/LaunchSpreadSheetWorkFlowResponse'
PASSING
...
COLUMNS
LaunchSpreadSheetWorkFlowResponse xmlType PATH '.'
) xmlt1
CROSS JOIN XMLTABLE(
'.'
PASSING
xmlt1.LaunchSpreadSheetWorkFlowResponse
COLUMNS
instanceNumber varchar2(20) PATH 'instanceNumber'
) xmlt2
;
I'm not sure it's worth it here, and I'd be tempted to stick to the wildcard version.
db<>fiddle showing both.

QlikSense Script Issue : I'm getting multiple records for some Casenumbers with different state like " Progress' & "On Hold"

LOAD
number as [Case Number],
number as key_case,
short_description as Description,
ApplyMap('map_CustomerDeliveryGroup',dv_company,'N/A') as CustomerGroupNo,
mid(dv_priority,5) as Priority,
dv_business_service as Service,
dv_state as State,
dv_category as ServiceCI,
DATE(SUBFIELD(sys_created_on,' ',1)) as key_reported_date,
IF(DATE(SUBFIELD(sys_created_on,' ',1)) > monthstart(today()-360),'1','0') as InYear,
text(applymap('map_wanted_customers',upper(dv_company),0)) as WantedCustomer,
contact_type,
dv_contact as contact,
dv_company as Customer,
dv_assignment_group as Assigned_Group,
dv_assigned_to as Assignee
FROM [lib];
dv_task as key_case,
dv_stage as ResponseStage,
business_percentage as ResponseLeft,
IF(business_percentage <= 100, 'Met','Missed') as SLA_Response_MeasurementStatus_Name,
DATE(SUBFIELD(end_time ,' ',1)) as ResponseTime
FROM [lib]
WHERE wildmatch(dv_sla,'*Response*')
and exists([Case Number],dv_task)
and dv_stage = 'Completed';
your table probably contains records from different stage of case, something like log,
there is second table with key_case which makes joins and it can also affect data,
it is really hard to give exact answer without seeing data model/data or just qvw file

Oracle XML Parsing - ORA-19202 and LPX-00601

I am new to XML parsing in oracle, I am getting ORA-19202: Error occurred in XML processing and LPX-00601: Invalid token for below query. Can anyone please help ?
TABLENAME = PARSEXML
COLUMN1('ID') = VARCHAR |COLUMN2('XML') = CLOB
<?xml version="1.0" encoding="UTF-8"?>
<ns4:TSTCLOB xmlns:ns4="http://example.org/test" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<ns4:Rqst>
<ns2:Initiation>
<ns2:InitiationDetail>
<ns3:Channel>WEB</ns3:Channel>
<ns3:Unit>ABCD</ns3:Unit>
</ns2:InitiationDetail>
</ns2:Initiation>
</ns4:Rqst>
</ns4:TSTCLOB>
SELECT ID, EXTRACT(xmltype(XML), '\ns4:TSTCLOB\ns4:Rqst\ns2:Initiation\ns2:InitiationDetail\ns3:Unit') "unit"
FROM PARSEXML WHERE ID = '123'
1) Your example xml is not valid. It is using 4 namespace but only 2 are declared. You have to add this xmlns:ns2="Namespace2" xmlns:ns3="Namespace3"
<ns4:TSTCLOB xmlns:ns4="http://example.org/test" xmlns:ns2="Namespace2" xmlns:ns3="Namespace3" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<ns4:Rqst>
<ns2:Initiation>
<ns2:InitiationDetail>
<ns3:Channel>WEB</ns3:Channel>
<ns3:Unit>ABCD</ns3:Unit>
</ns2:InitiationDetail>
</ns2:Initiation>
</ns4:Rqst>
</ns4:TSTCLOB>
2) In xpath you have to use slash instead of backslash \ -> / = '/ns4:TSTCLOB/ns4:Rqst/ns2:Initiation/ns2:InitiationDetail/ns3:Unit'
3) Extract method has 3 parameters, the last one is namespace string. If your xml is using other namespace except default one you have to specify this in extract method.
Extract(xml, '/ns4:TSTCLOB/ns4:Rqst/ns2:Initiation/ns2:InitiationDetail/ns3:Unit','xmlns:ns4="http://example.org/test" xmlns:ns2="Namespace2" xmlns:ns3="Namespace3" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"')
4*) Extract,ExtractValue are deprecated , you should use xmltable or xmlquery
Try this approach (simplified the XML for testing purpose):
with tmp as(
select
xmltype(to_clob('<?xml version="1.0" encoding="UTF-8"?>
<TSTCLOB>
<Rqst>
<Initiation>
<InitiationDetail>
<Channel>WEB</Channel>
<Unit>ABCD</Unit>
</InitiationDetail>
</Initiation>
</Rqst>
</TSTCLOB>')) tmp_xml
from dual)
select
xml_tbl.Channel,
xml_tbl.Unit
from
tmp,
xmltable(
'/TSTCLOB/Rqst/Initiation/InitiationDetail' passing tmp.tmp_xml
columns
Channel varchar2(6) path 'Channel',
Unit varchar2(6) path 'Unit') xml_tbl

Oracle raises ORA-01722: invalid number during merge into with nested xmltable

I'm runnning the code that should parse xml and add it to my table. XML code is loaded from variable "s". Sample of my xml is:
<?xml version="1.0" encoding="utf-8"?><response>
<item>
<id>7294478</id>
<type>ad</type>
<stats list="true">
<period>
<day>2012-12-26</day>
<spent>132.00</spent>
<impressions>93315</impressions>
<clicks>4</clicks>
<reach>38039</reach>
</period>
<period>
<day>2012-12-27</day>
<impressions>7237</impressions>
<reach>4332</reach>
</period>
<period>
<day>2012-12-28</day>
<impressions>571</impressions>
<reach>452</reach>
</period>
</stats>
</item>
</response>
That's the part of code i'm trying to run:
MERGE INTO VK_AD_STATS r
USING (SELECT hmn.STATS_ID,
hmn.STATS_type,
items.STATS_day,
items.STATS_spent,
items.STATS_impressions,
items.STATS_clicks,
items.STATS_reach,
items.STATS_video_views,
items.STATS_video_views_half,
items.STATS_video_views_full,
items.STATS_video_clicks_site,
items.STATS_join_rate
FROM XMLTABLE('response/item' passing (SELECT xmltype(s) resp FROM dual)
COLUMNS STATS_ID NUMBER path '/item/id',
STATS_type VARCHAR2(2000) path '/item/type',
STATS_XML xmltype path '/item/stats/period'
)hmn ,
XMLTABLE('period' passing hmn.STATS_XML
COLUMNS STATS_day VARCHAR2(2000) path '/period/day',
STATS_spent NUMBER path '/period/spent',
STATS_impressions NUMBER path '/period/impressions',
STATS_clicks NUMBER path '/period/clicks',
STATS_reach NUMBER path '/period/reach',
STATS_video_views NUMBER path '/period/video_views',
STATS_video_views_half NUMBER path '/period/video_views_half',
STATS_video_views_full NUMBER path '/period/video_views_full',
STATS_video_clicks_site NUMBER path '/period/_video_clicks_site ',
STATS_join_rate NUMBER path '/period/join_rate'
) items) proc
ON (r.STATS_ID = proc.STATS_ID and r.STATS_day = proc.STATS_day)
WHEN MATCHED THEN UPDATE SET r.STATS_type = proc.STATS_type,
r.STATS_spent = proc.STATS_spent,
r.STATS_impressions = proc.STATS_impressions,
r.STATS_clicks = proc.STATS_clicks,
r.STATS_reach = proc.STATS_reach,
r.STATS_video_views = proc.STATS_video_views,
r.STATS_video_views_half = proc.STATS_video_views_half,
r.STATS_video_views_full = proc.STATS_video_views_full,
r.STATS_video_clicks_site = proc.STATS_video_clicks_site,
r.STATS_join_rate = proc.STATS_join_rate
WHEN NOT MATCHED THEN INSERT (r.STATS_ID,
r.STATS_type,
r.STATS_day,
r.STATS_spent,
r.STATS_impressions,
r.STATS_clicks,
r.STATS_reach,
r.STATS_video_views,
r.STATS_video_views_half,
r.STATS_video_views_full,
r.STATS_video_clicks_site,
r.STATS_join_rate
)
VALUES (proc.STATS_ID,
proc.STATS_type,
proc.STATS_day,
proc.STATS_spent,
proc.STATS_impressions,
proc.STATS_clicks,
proc.STATS_reach,
proc.STATS_video_views,
proc.STATS_video_views_half,
proc.STATS_video_views_full,
proc.STATS_video_clicks_site,
proc.STATS_join_rate
);
COMMIT;
But it raises ORA-01722: invalid number
Extract the spent column as text and then convert it specifying the NLS_NUMERIC_CHARCTERS to use as decimal separator:
SELECT hmn.STATS_ID,
hmn.STATS_type,
items.STATS_day,
TO_NUMBER(
items.STATS_spent,
'99999999999999999999D99',
'NLS_NUMERIC_CHARACTERS='',.'''
) AS stats_spent,
items.STATS_impressions,
items.STATS_clicks,
items.STATS_reach,
items.STATS_video_views,
items.STATS_video_views_half,
items.STATS_video_views_full,
items.STATS_video_clicks_site,
items.STATS_join_rate
FROM XMLTABLE(
'/response/item'
PASSING XMLTYPE(s)
COLUMNS STATS_ID NUMBER path '/item/id',
STATS_type VARCHAR2(2000) path '/item/type',
STATS_XML xmltype path '/item/stats/period'
) hmn,
XMLTABLE(
'/period'
PASSING hmn.STATS_XML
COLUMNS STATS_day VARCHAR2(2000) path '/period/day',
STATS_spent VARCHAR2(23) path '/period/spent',
STATS_impressions NUMBER path '/period/impressions',
STATS_clicks NUMBER path '/period/clicks',
STATS_reach NUMBER path '/period/reach',
STATS_video_views NUMBER path '/period/video_views',
STATS_video_views_half NUMBER path '/period/video_views_half',
STATS_video_views_full NUMBER path '/period/video_views_full',
STATS_video_clicks_site NUMBER path '/period/_video_clicks_site',
STATS_join_rate NUMBER path '/period/join_rate'
) items
Your problem isn't XML related at all - this:
<spent>132.00</spent>
doesn't parse as a number if your NLS settings use , as a decimal separator.
Change your NLS settings to use . as decimal separator, e.g. by running this PL/SQL block:
begin
DBMS_SESSION.SET_NLS ('NLS_LANGUAGE' ,'AMERICAN');
DBMS_SESSION.SET_NLS ('NLS_TERRITORY','AMERICA');
end;
and your code should work.

Oracle JPG metadata xpath from XMLTYPE column

I have a tavle storing photos. With a pl/sql script i extract the image metadata to the exifmetadata xmltype column.
I would like to select the elements one by one, but i always get null back and i don't know what is the issue with my xpath expression.
<exifMetadata xmlns="http://xmlns.oracle.com/ord/meta/exif" xsi:schemaLocation="http://xmlns.oracle.com/ord/meta/exif http://xmlns.oracle.com/ord/meta/exif" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<TiffIfd>
<Make tag="271">Apple</Make>
<Model tag="272">iPhone 4S</Model>
<Orientation tag="274">top left</Orientation>
<XResolution tag="282">72.0</XResolution>
<YResolution tag="283">72.0</YResolution>
<ResolutionUnit tag="296">inches</ResolutionUnit>
<Software tag="305">6.0.1</Software>
<DateTime tag="306">2012-11-16T13:31:15</DateTime>
<YCbCrPositioning tag="531">centered</YCbCrPositioning>
</TiffIfd>
<ExifIfd tag="34665">
<ExposureTime tag="33434">0.004405286</ExposureTime>
<FNumber tag="33437">2.4</FNumber>
<ExposureProgram tag="34850">Normal program</ExposureProgram>
<ExifVersion tag="36864">0221</ExifVersion>
<DateTimeOriginal tag="36867">2012-11-16T12:49:58</DateTimeOriginal>
<DateTimeDigitized tag="36868">2012-11-16T12:49:58</DateTimeDigitized>
<ComponentsConfiguration tag="37121">Y</ComponentsConfiguration>
<ShutterSpeedValue tag="37377">7.82697</ShutterSpeedValue>
<ApertureValue tag="37378">2.5260692</ApertureValue>
<BrightnessValue tag="37379">6.641153</BrightnessValue>
<MeteringMode tag="37383">Pattern</MeteringMode>
<Flash tag="37385">
<Fired>No</Fired>
</Flash>
<FocalLength tag="37386">4.28</FocalLength>
<FlashpixVersion tag="40960">0100</FlashpixVersion>
<ColorSpace tag="40961">sRGB</ColorSpace>
<PixelXDimension tag="40962">2902</PixelXDimension>
<PixelYDimension tag="40963">1938</PixelYDimension>
<SensingMethod tag="41495">One-chip color area</SensingMethod>
<ExposureMode tag="41986">Auto exposure</ExposureMode>
<WhiteBalance tag="41987">Auto</WhiteBalance>
<FocalLengthIn35mmFilm tag="41989">35</FocalLengthIn35mmFilm>
<SceneCaptureType tag="41990">Standard</SceneCaptureType>
</ExifIfd>
</exifMetadata>
And the SQL:
SELECT
p.metaexif.extract('//exifMetadata/TiffIfd/Make/text()').getStringVal() "Model"
FROM scott.photos p
WHERE id=22
;
The id 22 record exist that is sure.
you have a default namespace set so you have to cope with this.
eg use this:
select extractvalue(p.metaexif,'/exifMetadata/TiffIfd/Make',
'xmlns="http://xmlns.oracle.com/ord/meta/exif"')

Resources