Get comma separated values from an xml in SQL - sql

I am calling Scalar UDF from a stored procedure to get a column value. Inside the scalar UDF I have an xml and I have to get the comma separated values of a particular node. I used Cross apply but it caused huge performance bottleneck because stored procedure is actually used to fetch reports.
There is a table [Traveler] which has a field ID, BookingID(can be duplicate) and FareDetails. Inside the FareDetails we are storing the xml.
The logic inside UDF is as follows :
1st Solution , Using Cross Apply :
ALTER FUNCTION [dbo].[GetBookingInfo] (#BookingID bigint, #InfoID smallint) RETURNS VARCHAR(1024) AS
BEGIN
DECLARE #InfoCSV VARCHAR(1024)
--
-- Fare Basis: InfoID = 1
--
IF #InfoID = 1
BEGIN
SELECT #InfoCSV = (SELECT
(PTSD.PSTDNode.value('(FBC)[1]', 'VARCHAR(1024)') + ',') [text()]
FROM
[Traveler]
CROSS APPLY [FareDetails].nodes('/AirFareInfo/PTSDPFS/PTSD') PTSD(PSTDNode)
WHERE
[BookingID] = #BookingID
ORDER BY
ID ASC
FOR XML PATH (''))
IF #InfoCSV IS NOT NULL AND LEN(#InfoCSV) > 0
SET #InfoCSV = LEFT(#InfoCSV, LEN(#InfoCSV) - 1)
END
RETURN #InfoCSV
2nd solution , without cross apply :
ALTER FUNCTION [dbo].[GetBookingInfo] (#BookingID bigint, #InfoID smallint) RETURNS VARCHAR(1024) AS
BEGIN
DECLARE #InfoCSV VARCHAR(1024)
--
-- Fare Basis: InfoID = 1
--
IF #InfoID = 1
BEGIN
SELECT #InfoCSV = (SELECT TOP 1 REPLACE(FareDetails.query(N'data(/AirFareInfo/PTSDPFS/PTSD/FBC)').value('(text())[1]','nvarchar(100)'),' ',',')
FROM [Traveler]
WHERE
[BookingID] = #BookingID)
IF #InfoCSV IS NOT NULL AND LEN(#InfoCSV) > 0
SET #InfoCSV = LEFT(#InfoCSV, LEN(#InfoCSV) - 1)
END
RETURN #InfoCSV
The 2nd solution is saving lot of time , but when we have duplicate booking ID's then it is not concatenating all the values of FBC .
e.g. :
1)If BookingID is unique and we have FareDetail xml as follows then output should be be AP,AP
2)If BookingID is not unique(coming twice) and we have FareDetail xml as follows then output should be be AP,AP,AP,AP corresponding to both BookingID.
The xml is as follows :
<AirFareInfo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" IPFA="false">
<PT>Flight</PT>
<FPMID>0</FPMID>
<PTID>1</PTID>
<FS>
<CID>2</CID>
<Value>0</Value>
</FS>
<TF>
<CID xsi:nil="true" />
<Value>0</Value>
</TF>
<VF>
<CID>2</CID>
<Value>0</Value>
</VF>
<VD>
<CID>2</CID>
<Value>0</Value>
</VD>
<VCR xsi:nil="true" />
<VC>
<CID>2</CID>
<Value>0</Value>
</VC>
<VFC>
<CID>2</CID>
<Value>0</Value>
</VFC>
<VST />
<VIT />
<AAPFVDR xsi:nil="true" />
<CC>
<CID>2</CID>
<Value>0</Value>
</CC>
<D>
<CID>2</CID>
<Value>514.15</Value>
</D>
<PD>
<CID>2</CID>
<Value>0</Value>
</PD>
<EBF>
<CID>2</CID>
<Value>0</Value>
</EBF>
<CST>
<DL>
<ATRID>13</ATRID>
<OB>
<CID>2</CID>
<Value>74.04</Value>
</OB>
<OC>
<CID>2</CID>
<Value>0.00</Value>
</OC>
<OS>
<CID>2</CID>
<Value>0.00</Value>
</OS>
<OF>
<CID>2</CID>
<Value>50.83</Value>
</OF>
<OP>
<CID>2</CID>
<Value>0.00</Value>
</OP>
<C>
<CID>2</CID>
<Value>0</Value>
</C>
<IBF>false</IBF>
<D>2014-06-09T14:57:53.521Z</D>
</DL>
</CST>
<CIT />
<CRMR xsi:nil="true" />
<CRM>
<CID>2</CID>
<Value>0</Value>
</CRM>
<TL ATC="Tax" PC="" DEN="User Development Fee - Arrival (UDF)">
<TID xsi:nil="true" />
<Amount>
<CID>2</CID>
<Value>75.00</Value>
</Amount>
</TL>
<TL ATC="Tax" PC="" DEN="Passenger Service Fee">
<TID xsi:nil="true" />
<Amount>
<CID>2</CID>
<Value>146.00</Value>
</Amount>
</TL>
<TL ATC="Tax" PC="" DEN="User Development Fee - Departure (UDF)">
<TID xsi:nil="true" />
<Amount>
<CID>2</CID>
<Value>1681.00</Value>
</Amount>
</TL>
<TL ATC="Tax" PC="" DEN="Cute Fee">
<TID xsi:nil="true" />
<Amount>
<CID>2</CID>
<Value>50.00</Value>
</Amount>
</TL>
<TL ATC="Tax" PC="" DEN="Government Service Tax">
<TID xsi:nil="true" />
<Amount>
<CID>2</CID>
<Value>151.00</Value>
</Amount>
</TL>
<TL ATC="Tax" PC="" DEN="User Development Fee - Arrival (UDF)">
<TID xsi:nil="true" />
<Amount>
<CID>2</CID>
<Value>833.00</Value>
</Amount>
</TL>
<TL ATC="Tax" PC="" DEN="Passenger Service Fee">
<TID xsi:nil="true" />
<Amount>
<CID>2</CID>
<Value>1132.00</Value>
</Amount>
</TL>
<TL ATC="Tax" PC="" DEN="User Development Fee - Departure (UDF)">
<TID xsi:nil="true" />
<Amount>
<CID>2</CID>
<Value>76.00</Value>
</Amount>
</TL>
<TL ATC="Tax" PC="" DEN="Government Service Tax">
<TID xsi:nil="true" />
<Amount>
<CID>2</CID>
<Value>148.00</Value>
</Amount>
</TL>
<PTSDPFS>
<PTSD IO="false">
<FBC>AP</FBC>
<ACD RBD="" ACCID="1" MCT="Super Sale Fare(AP)" INC="false" />
<ATSID xsi:nil="true" />
</PTSD>
</PTSDPFS>
<PTSDPFS>
<PTSD IO="false">
<FBC>AP</FBC>
<ACD RBD="" ACCID="1" MCT="Super Sale Fare(AP)" INC="false" />
<ATSID xsi:nil="true" />
</PTSD>
</PTSDPFS>
<RuleDetails>
<TRS xsi:nil="true" />
<PP xsi:nil="true" />
<II xsi:nil="true" />
<LTD xsi:nil="true" />
</RuleDetails>
</AirFareInfo>
Please suggest how it can be done keeping performance in mind.

This is a fully working example.
You told us, that performance matters, so do not use scalar UDF!
Try it like this (next time it's your job to create a (reduced!!!) MCVE:
CREATE DATABASE testDB;
GO
USE testDB;
GO
CREATE TABLE Booking(BookingID INT CONSTRAINT PK_Booking PRIMARY KEY
,SomeBookingData VARCHAR(100));
INSERT INTO Booking VALUES(1,'Booking 1'),(2,'Booking 2');
CREATE TABLE BookingInfo(BookingID INT CONSTRAINT FK_BookingInfo_BookingID FOREIGN KEY REFERENCES Booking(BookingID)
,SomeOtherInfo VARCHAR(100)
,FareDetails XML);
INSERT INTO BookingInfo VALUES
(1,'First row for ID=1, returns AP,AP'
,N'<AirFareInfo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" IPFA="false">
<PTSDPFS>
<PTSD IO="false">
<FBC>AP</FBC>
</PTSD>
</PTSDPFS>
<PTSDPFS>
<PTSD IO="false">
<FBC>AP</FBC>
</PTSD>
</PTSDPFS>
</AirFareInfo>')
,(1,'Second row for ID=1, returns XY,MN'
,N'<AirFareInfo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" IPFA="false">
<PTSDPFS>
<PTSD IO="false">
<FBC>XY</FBC>
</PTSD>
</PTSDPFS>
<PTSDPFS>
<PTSD IO="false">
<FBC>MN</FBC>
</PTSD>
</PTSDPFS>
</AirFareInfo>')
,(2,'row with ID=2, returns AA,BB'
,N'<AirFareInfo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" IPFA="false">
<PTSDPFS>
<PTSD IO="false">
<FBC>AA</FBC>
</PTSD>
</PTSDPFS>
<PTSDPFS>
<PTSD IO="false">
<FBC>BB</FBC>
</PTSD>
</PTSDPFS>
</AirFareInfo>');
GO
--This is the function. It returns as table and is fully inlined (no BEGIN...END!)
CREATE FUNCTION dbo.CreateBookingInfoCSV(#BookingID INT)
RETURNS TABLE
AS
RETURN
SELECT STUFF(
(
SELECT ','+REPLACE(FareDetails.query(N'data(/AirFareInfo/PTSDPFS/PTSD/FBC)').value(N'.',N'nvarchar(max)'),' ',',')
FROM BookingInfo AS bi
WHERE bi.BookingID=#BookingID
FOR XML PATH('')
),1,1,'') AS BookingInfoCSV;
GO
--Hint the trick with XQuery data() function will break, if your values contain blanks!
--The following SELECT calls all rows from Booking-table and gets the fitting details
SELECT b.BookingID
,b.SomeBookingData
,A.BookingInfoCSV
FROM Booking AS b
OUTER APPLY dbo.CreateBookingInfoCSV(b.BookingID) AS A;
GO
--Clean up (carefull with real data!)
USE master;
GO
DROP DATABASE testDB;
--The result
BookingID SomeBookingData BookingInfoCSV
1 Booking 1 AP,AP,XY,MN
2 Booking 2 AA,BB

Related

PLSQL - REGEXP_SUBSTR Remove XML Tags

I currently have a payload that was generated by oracle xml gateway that I need to pull some exact information out. The payload information is store within a db table meaning that I am attempting to us regexp_substr to accomplish this task.
This is the tag that is in the middle of the XML document
<IDCODE>S2200</IDCODE>
"<?xml version="1.0" encoding="UTF-8" standalone='no'?>
<!DOCTYPE PROCESS_INVOICE_002 SYSTEM "asfasdf.dtd">
<!-- Oracle eXtensible Markup Language Gateway Server -->
<PROCESS_INVOICE_002>
<CNTROLAREA>
<BSR>
<VERB value="PROCESS"/>
<NOUN value="INVOICE"/>
<REVISION value="002"/>
</BSR>
<SENDER>
<LOGICALID/>
<COMPONENT/>
<TASK/>
<REFERENCEID/>
<CONFIRMATION/>
<LANGUAGE/>
<CODEPAGE/>
<AUTHID/>
</SENDER>
<DATETIME qualifier="CREATION">
<YEAR/>
<MONTH/>
<DAY/>
<HOUR/>
<MINUTE/>
<SECOND/>
<SUBSECOND/>
<TIMEZONE/>
</DATETIME>
</CNTROLAREA>
<DATAAREA>
<PROCESS_INVOICE>
<INVHEADER>
<AMOUNT qualifier="DOCUMENT" type="T" index="1">
<VALUE>78538</VALUE>
<NUMOFDEC>8</NUMOFDEC>
<SIGN>+</SIGN>
<CURRENCY>USD</CURRENCY>
<DRCR>D</DRCR>
</AMOUNT>
<DATETIME qualifier="DOCUMENT" index="1">
<YEAR>2020</YEAR>
<MONTH>11</MONTH>
<DAY>28</DAY>
<HOUR>00</HOUR>
<MINUTE>00</MINUTE>
<SECOND>00</SECOND>
<SUBSECOND>0000</SUBSECOND>
<TIMEZONE>+0000</TIMEZONE>
</DATETIME>
<DOCUMENTID>81989184</DOCUMENTID>
<DESCRIPTN/>
<DOCTYPE>INV</DOCTYPE>
<PAYMETHOD/>
<REASONCODE/>
<USERAREA>
<NOTEREFCODE/>
<NOTESREF/>
<VENDNUMQUAL>IA</VENDNUMQUAL>
<VENDNUM>98181</VENDNUM>
<DEPTNUMQUAL>DP</DEPTNUMQUAL>
<DEPTNUM>85</DEPTNUM>
<ORDNUMQUAL/>
<ORDNUM>0</ORDNUM>
<CUSTCODEQUAL/>
<CUSTCODE/>
<NETDAYS/>
<DATETIMEQUAL/>
<FOBCODE/>
<UOM/>
<TOTALQUANTITY/>
</USERAREA>
<PARTNER>
<NAME index="1">COMPANY NAME</NAME>
<ONETIME/>
<PARTNRID/>
<PARTNRTYPE>Supplier</PARTNRTYPE>
<SYNCIND/>
<ACTIVE/>
<CURRENCY/>
<DESCRIPTN/>
<DUNSNUMBER/>
<GLENTITYS/>
<PARENTID/>
<PARTNRIDX/>
<PARTNRRATG/>
<PARTNRROLE/>
<PAYMETHOD/>
<TAXEXEMPT/>
<TAXID/>
<TERMID/>
<USERAREA>
<IDQUAL/>
<IDCODE/>
</USERAREA>
<CONTACT>
<NAME index="1">PROFILE</NAME>
<CONTCTTYPE/>
<DESCRIPTN/>
<EMAIL/>
<FAX index="1"/>
<TELEPHONE index="1"/>
<USERAREA/>
</CONTACT>
</PARTNER>
<PARTNER>
<NAME index="1">CUSTOMER NAME</NAME>
<ONETIME/>
<PARTNRID>981698198</PARTNRID>
<PARTNRTYPE>ShipTo</PARTNRTYPE>
<SYNCIND/>
<ACTIVE/>
<CURRENCY/>
<DESCRIPTN/>
<DUNSNUMBER/>
<GLENTITYS/>
<PARENTID/>
<PARTNRIDX/>
<PARTNRRATG/>
<PARTNRROLE/>
<PAYMETHOD/>
<TAXEXEMPT/>
<TAXID/>
<TERMID/>
<USERAREA>
<IDQUAL>ZZ</IDQUAL>
<IDCODE>S2200</IDCODE>
</USERAREA>
<ADDRESS>
<ADDRLINE index="1">123 MAIN STREET</ADDRLINE>
<ADDRTYPE/>
<CITY>HAM CITY</CITY>
<COUNTRY>United States</COUNTRY>
<COUNTY>NEW YORK</COUNTY>
<DESCRIPTN/>
<FAX index="1"/>
<POSTALCODE>18080</POSTALCODE>
<REGION/>
<STATEPROVN>NY</STATEPROVN>
<TAXJRSDCTN/>
<TELEPHONE index="1"/>
<URL/>
<USERAREA/>
</ADDRESS>
REGEX that I am using in the query
TRIM(regexp_substr(ed.payload, '?.+(</IDCODE>)')) Store_NUM,
TRIM(regexp_substr(ed.payload, '(^IDCODE)?.+(</IDCODE>)')) Store_Number
The Outcome that I am receiving from the above SQL regexp_substr. The issue is that I have made it to the correct tab but I can't figure out how to strip the \<IDCODE> and the \</IDCODE> for the output
-Field can have 4 or 5 chars
-letters or numbers
<IDCODE>S2200</IDCODE> Store_NUM
<IDCODE>S2200</IDCODE> Store_Number
I believe you are looking for this if I am understanding you correctly. Return everything in the group between the tags.
SELECT REGEXP_SUBSTR('<IDCODE>S2200</IDCODE>', '<IDCODE>(.*)</IDCODE>', 1, 1, NULL, 1) Store_Number
from dual;
STORE_NUMBER
------------
S2200
1 row selected.

Find element or attribute value anywhere in XML

I am trying to find the value of an element / attribute regardless of where it exists in the XML.
XML:
<?xml version="1.0" encoding="UTF-8"?>
<cXML payloadID="12345677-12345567" timestamp="2017-07-26T09:11:05">
<Header>
<From>
<Credential domain="1212">
<Identity>01235 </Identity>
<SharedSecret/>
</Credential>
</From>
<To>
<Credential domain="1212">
<Identity>01234</Identity>
</Credential>
</To>
<Sender>
<UserAgent/>
<Credential domain="8989">
<Identity>10678</Identity>
<SharedSecret>Testing123</SharedSecret>
</Credential>
</Sender>
</Header>
<Request deploymentMode="Prod">
<ConfirmationRequest>
<ConfirmationHeader noticeDate="2017-07-26T09:11:05" operation="update" type="detail">
<Total>
<Money>0.00</Money>
</Total>
<Shipping>
<Description>Delivery</Description>
</Shipping>
<Comments>WO# generated</Comments>
</ConfirmationHeader>
<OrderReference orderDate="2017-07-25T15:22:11" orderID="123456780000">
<DocumentReference payloadID="5678-4567"/>
</OrderReference>
<ConfirmationItem quantity="1" lineNumber="1">
<ConfirmationStatus quantity="1" type="detail">
<ItemIn quantity="1">
<ItemID>
<SupplierPartID>R954-89</SupplierPartID>
</ItemID>
<ItemDetail>
<UnitPrice>
<Money currency="USD">0.00</Money>
</UnitPrice>
<Description>Test Descritpion 1</Description>
<UnitOfMeasure>QT</UnitOfMeasure>
</ItemDetail>
</ItemIn>
</ConfirmationStatus>
</ConfirmationItem>
<ConfirmationItem quantity="1" lineNumber="2">
<ConfirmationStatus quantity="1" type="detail">
<ItemIn quantity="1">
<ItemID>
<SupplierPartID>Y954-89</SupplierPartID>
</ItemID>
<ItemDetail>
<UnitPrice>
<Money currency="USD">0.00</Money>
</UnitPrice>
<Description>Test Descritpion 2</Description>
<UnitOfMeasure>QT</UnitOfMeasure>
</ItemDetail>
</ItemIn>
</ConfirmationStatus>
</ConfirmationItem>
</ConfirmationRequest>
</Request>
</cXML>
I want to get the value of the payloadID on the DocumentReference element. This is what I have tried so far:
BEGIN
Declare #Xml xml
Set #Xml = ('..The XML From Above..' as xml)
END
--no value comes back
Select c.value('(/*/DocumentReference/#payloadID)[0]','nvarchar(max)') from #Xml.nodes('//cXML') x(c)
--no value comes back
Select c.value('#payloadID','nvarchar(max)') from #Xml.nodes('/cXML/*/DocumentReference') x(c)
--check if element exists and it does
Select #Xml.exist('//DocumentReference');
I tried this in an xPath editor: //DocumentReference/#payloadID
This does work, but I am not sure what the equivalent syntax is in SQL
Calling .nodes() (like suggested in comment) is an unecessary overhead...
Better try it like this:
SELECT #XML.value('(//DocumentReference/#payloadID)[1]','nvarchar(max)')
And be aware, that XPath starts counting at 1. Your example with [0] cannot work...
--no value comes back
Select c.value('(/*/DocumentReference/#payloadID)[0]','nvarchar(max)') from...

FORXML SQL Group By Element

I am trying to group some elements together under one node. This is my current SQL;
declare #xml xml
set #xml = (
select (
select
'DERIVED' '#type',
m.NuixDerivedFieldName '#name', (
SELECT
NuixFieldType as 'metadata/#type',
NuixFieldName as 'metadata/#name'
from eddsdbo.MetadataMapping m1
where m1.NuixDerivedFieldName = m.NuixDerivedFieldName
for xml path ('first-non-blank'), type
)
from (select distinct NuixDerivedFieldName from eddsdbo.MetadataMapping) m
for xml path ('metadata'))
)
;WITH XMLNAMESPACES(DEFAULT 'http://nuix.com/fbi/metadata-profile')
select #xml for XML PATH ('metadata-list'), ROOT ('metadata-profile')
Which gives me the following output;
<metadata-profile xmlns="http://nuix.com/fbi/metadata-profile">
<metadata-list>
<metadata type="DERIVED" name="Barcode" xmlns="">
<first-non-blank>
<metadata type="CUSTOM" name="Barcode" />
</first-non-blank>
<first-non-blank>
<metadata type="EVIDENCE" name="Barcode" />
</first-non-blank>
</metadata>
I want to group together elements together which have the same 'name' attribute of the metadata element under the <first-non-blank> element.
The desired output should be;
<metadata-profile xmlns="http://nuix.com/fbi/metadata-profile">
<metadata-list>
<metadata type="DERIVED" name="Barcode" xmlns="">
<first-non-blank>
<metadata type="CUSTOM" name="Barcode" />
<metadata type="EVIDENCE" name="Barcode" />
</first-non-blank>
</metadata>
...
My database looks something like this;
NuixFieldName NuixFieldType NuixDerivedFieldName
------------------------------ ------------------------------ ------------------------------
_EmailEntryID PROPERTY EmailEntryID
Audited Audited Audited
Author PROPERTY Author
Barcode CUSTOM Barcode
Barcode EVIDENCE Barcode
I would also like to remove the xlmns namespace identifier from the metadata elements.
Thanks in advance!
You could try this
DECLARE #SampleData AS TABLE
(
NuixFieldName varchar(20),
NuixFieldType varchar(20),
NuixDerivedFieldName varchar(20)
)
INSERT INTO #SampleData
VALUES
('_EmailEntryID','PROPERTY','EmailEntryID'),
('Audited', 'Audited ','Audited'),
('Author ', 'PROPERTY','Author '),
('Barcode', 'CUSTOM ','Barcode'),
('Barcode', 'EVIDENCE','Barcode')
DECLARE #xml XML
SET #xml = (
SELECT
-- sd.NuixDerivedFieldName AS [#name],
'DERIVED' AS [#type],
sd.NuixDerivedFieldName AS [#name],
(
SELECT
sd2.NuixFieldType as '#type',
sd2.NuixFieldName as '#name'
FROM #SampleData sd2 WHERE sd2.NuixDerivedFieldName = sd.NuixDerivedFieldName
FOR XML PATH ('metadata'),ROOT('first-non-blank'), TYPE
)
FROM (select DISTINCT sd.NuixDerivedFieldName from #SampleData sd ) sd
FOR XML PATH('metadata'), ROOT('metadata-list'),TYPE
)
;WITH XMLNAMESPACES(DEFAULT 'http://nuix.com/fbi/metadata-profile')
SELECT #xml FOR XML PATH (''),ROOT('metadata-profile')
return:
<metadata-profile xmlns="http://nuix.com/fbi/metadata-profile">
<metadata-list>
<metadata type="DERIVED" name="Audited">
<first-non-blank>
<metadata type="Audited " name="Audited" />
</first-non-blank>
</metadata>
<metadata type="DERIVED" name="Author ">
<first-non-blank>
<metadata type="PROPERTY" name="Author " />
</first-non-blank>
</metadata>
<metadata type="DERIVED" name="Barcode">
<first-non-blank>
<metadata type="CUSTOM " name="Barcode" />
<metadata type="EVIDENCE" name="Barcode" />
</first-non-blank>
</metadata>
<metadata type="DERIVED" name="EmailEntryID">
<first-non-blank>
<metadata type="PROPERTY" name="_EmailEntryID" />
</first-non-blank>
</metadata>
</metadata-list>
</metadata-profile>

Read XML data in SQL

I want to query data from XML. I have managed to retrive data from another set of XML data but this are a bit problematic.
Bellow you see the data and the query that does not retrive any data.
DECLARE #xml XML
SET #xml=N'<DocumentXML>
<LoadApplicationResult xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/Reaktor.Applikator.DTO">
<Application>
<EmbeddedProductList>
<EmbeddedProduct>
<Flag>false</Flag>
<CustomData>
<root xmlns="">
<Guaranteer ChangeTime="2012-04-28T08:50:07.5706054+02:00" ChangedBy="sven" OldValue="">
<Text>4</Text>
</Guaranteer>
<PercentGuarantee ChangeTime="2012-04-28T08:50:07.5706054+02:00" ChangedBy="sven" OldValue="">
<Number>100</Number>
</PercentGuarantee>
</root>
</CustomData>
<DataChangeTime>2014-04-28T08:50:07.5706054+02:00</DataChangeTime>
<ID>12</ID>
<FinanceSeparately>false</FinanceSeparately>
<Guid>5349efcd-457c-4423-b4bb-a28f97dd5e64</Guid>
<PluginData i:nil="true" />
<PriceCalcTime>2014-04-28T08:50:09.2580946+02:00</PriceCalcTime>
<Data>
<root xmlns="">
<root TableId="192">
<Generic.TypeCode>abba</Generic.TypeCode>
</root>
</root>
</Data>
</EmbeddedProduct>
<EmbeddedProduct>
<Flag>false</Flag>
<CustomData i:nil="true" />
<DataChangeTime>1954-10-03T00:00:00</DataChangeTime>
<ID>30</ID>
<FinanceSeparately>false</FinanceSeparately>
<Guid>d587b9b4-94df-4d9b-ba0d-2fdc62823a17</Guid>
<PluginData i:nil="true" />
<PriceCalcTime>2014-04-28T08:49:55.8831802+02:00</PriceCalcTime>
<Data>
<root xmlns="">
<root TableId="013">
<EmbProd.CMSPrice>0</EmbProd.CMSPrice>
<EmbProd.MonthFee Operator="DBLMUL" Target="CUSTOM.EPTermFee.ADD" Source="XPATH://PaySeries[1]/TermLength" DFValue="200">200</EmbProd.MonthFee>
</root>
<root TableId="759" GroupText="210" GroupText0="210">
<Flag>ink</Flag>
<Generic.TypeCode>fil</Generic.TypeCode>
</root>
</root>
</Data>
</EmbeddedProduct>
<EmbeddedProduct>
<Flag>false</Flag>
<CustomData>
<root xmlns="" />
</CustomData>
<DataChangeTime>2012-04-26T14:41:26.4232222+02:00</DataChangeTime>
<ID>16</ID>
<FinanceSeparately>false</FinanceSeparately>
<Guid>c2e2343f-a5d6-43c8-aa18-c43419d20165</Guid>
<PluginData i:nil="true" />
<PriceCalcTime>2014-04-28T08:49:55.8831802+02:00</PriceCalcTime>
<Data>
<root xmlns="">
<root TableId="102">
<EmbProd.MonthFee Operator="DBLMUL" Target="CUSTOM.EPTermFee.ADD" Source="XPATH://PaySeries[1]/TermLength" DFValue="300">300</EmbProd.MonthFee>
<EP.GenericCost Target="COST">114</EP.GenericCost>
</root>
<root TableId="102" GroupText="11" GroupText0="7">
<EP.TermCount Target="DBLMUL">13</EP.TermCount>
</root>
<root TableId="102" GroupText="210" GroupText0="210">
<Generic.TypeCode>frodinge</Generic.TypeCode>
</root>
</root>
</Data>
</EmbeddedProduct>
</EmbeddedProductList>
</Application>
</LoadApplicationResult>
</DocumentXML>'
SELECT tab.col.value('(Flag)[1]', 'nvarchar(max)') AS Flag
,tab.col.value('(Data/root/EmbProd.MonthFee)[1]', 'nvarchar(max)') AS Value
,tab.col.value('(ID)[1]', 'nvarchar(max)') AS Product
FROM #xml.nodes('/DocumentXML//LoadApplicationResult/Application/EmbeddedProductList/EmbeddedProduct') AS Tab(col)
The expected output should look like this:
+-------+-------+---------+
| Flag | Value | Product |
+-------+-------+---------+
| false | | 12 |
| false | 200 | 30 |
| true | 300 | 16 |
+-------+-------+---------+
You need to specify namespace
WITH XMLNAMESPACES ( 'http://schemas.datacontract.org/2004/07/Reaktor.Applikator.DTO' as x)
SELECT tab.col.value('(x:Flag)[1]', 'nvarchar(max)') AS Flag
,tab.col.value('(x:Data/root/root/EmbProd.MonthFee)[1]', 'nvarchar(max)') AS Value
,tab.col.value('(x:ID)[1]', 'nvarchar(max)') AS Product
FROM #xml.nodes('DocumentXML/x:LoadApplicationResult/x:Application/x:EmbeddedProductList/x:EmbeddedProduct') AS Tab(col);

XML Shredding into SQL Server

I have an XML doc in the following format.
<?xml version="1.0"?>
<Survey xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Name>US CDB GI MMPS </Name>
<Vendor Name="TWDS" />
<Versions>
<Version Name="All Functions Incumbent Weighted Accouting Value" Year="2014">
<JobMasters>
<JobMaster JobCode="AAS000-ALL-M1" JobTitle="AAS000 Administrative Services Generalist/Multidiscipline">
<Levels>
<Level LevelCode="M1">
<JobDetails>
<JobDetail Scope="Global Revenue">
<PayComponents>
<PayComponent Id="1" Name="Base" CompanyCount="16" IncumbentCount="281" IsPercent="false">
<Type>Base</Type>
<Pays>
<Pay Id="100" Stat="Average" Value="65.6">
<StatValue>Average</StatValue>
</Pay>
<Pay Id="10" Stat="P10" Value="41">
<StatValue>P10</StatValue>
</Pay>
<Pay Id="25" Stat="P25" Value="51.6">
<StatValue>P25</StatValue>
</Pay>
<Pay Id="101" Stat="Median" Value="66.3">
<StatValue>Median</StatValue>
</Pay>
<Pay Id="75" Stat="P75" Value="74.2">
<StatValue>P75</StatValue>
</Pay>
<Pay Id="90" Stat="P90" Value="89.5">
<StatValue>P90</StatValue>
</Pay>
</Pays>
</PayComponent>
</PayComponents>
</JobDetail>
</JobDetails>
</Level>
</Levels>
</JobMaster>
</JobMasters>
<Reports>
<Report Id="0" Name="standard" Type="Published" DatePublished="2015-04-06T14:29:52.7826312-07:00">
<JobDetails />
</Report>
</Reports>
</Version>
</Versions>
</Survey>
It is much larger, but this is the format. I want to dump these records into a denormalized table, containing everything from the Survey Name through Pay StatValue. I have tried many variations of the following script, but I can only correctly retrieve the Name of the Survey. Sometimes I can get the Survey Name and all StatValues concatenated as a string, all in one field like this..
US CDB GI MMPS BaseAverageP10P25MedianP75P90, and it is not useful or expected. Anyway, here is the script I'm using
--------WORKS----------------------------
DECLARE #myXML xml = (SELECT XMLData from XMLTest)
SELECT
T.C.value('Name[1]', 'varchar(255)') as Surveys--,
--T.C.value('JobCode[1]','varchar(255)') as JobCode
FROM #myXML.nodes('(/Survey)') as T(C)
-------------DOESN'T WORK-------------------------
DECLARE #myXML xml = (SELECT XMLData from XMLTest)
SELECT
T.C.value('Name[1]','varchar(255)') as VendorName
FROM #myXML.nodes('(/Survey/Vendor)') as T(C)
Here's an idea for you. I've tried to shred data for some and you can do it for others.
DECLARE #myXML xml = '<?xml version="1.0"?>
<Survey xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Name>US CDB GI MMPS </Name>
<Vendor Name="TWDS" />
<Versions>
<Version Name="All Functions Incumbent Weighted Accouting Value" Year="2014">
<JobMasters>
<JobMaster JobCode="AAS000-ALL-M1" JobTitle="AAS000 Administrative Services Generalist/Multidiscipline">
<Levels>
<Level LevelCode="M1">
<JobDetails>
<JobDetail Scope="Global Revenue">
<PayComponents>
<PayComponent Id="1" Name="Base" CompanyCount="16" IncumbentCount="281" IsPercent="false">
<Type>Base</Type>
<Pays>
<Pay Id="100" Stat="Average" Value="65.6">
<StatValue>Average</StatValue>
</Pay>
<Pay Id="10" Stat="P10" Value="41">
<StatValue>P10</StatValue>
</Pay>
<Pay Id="25" Stat="P25" Value="51.6">
<StatValue>P25</StatValue>
</Pay>
<Pay Id="101" Stat="Median" Value="66.3">
<StatValue>Median</StatValue>
</Pay>
<Pay Id="75" Stat="P75" Value="74.2">
<StatValue>P75</StatValue>
</Pay>
<Pay Id="90" Stat="P90" Value="89.5">
<StatValue>P90</StatValue>
</Pay>
</Pays>
</PayComponent>
</PayComponents>
</JobDetail>
</JobDetails>
</Level>
</Levels>
</JobMaster>
</JobMasters>
<Reports>
<Report Id="0" Name="standard" Type="Published" DatePublished="2015-04-06T14:29:52.7826312-07:00">
<JobDetails />
</Report>
</Reports>
</Version>
</Versions>
</Survey>'
DECLARE #docH INT;
EXEC [sys].[sp_xml_preparedocument] #docH OUTPUT, #myXML;
SELECT *
FROM OPENXML(#docH, '/Survey/Versions/Version/JobMasters/JobMaster/Levels/Level/JobDetails/JobDetail/PayComponents/PayComponent/Pays/Pay', 3)
WITH (Stat nvarchar(50) '#Stat',
Value DECIMAL '#Value',
Id INT '#Id',
PayComponentName NVARCHAR(50) '../../#Name',
PayComponentId int '../../#Id',
JobDetailScope NVARCHAR(20) '../../../../#Scope'
)
EXEC [sys].[sp_xml_removedocument] #docH