xQuery and T-SQL to Extract Data - sql

Got some basic XML as a XML datatype within SQL 2005. One record/row looks like this
<doc>
<level1>
<level2>
<name>James</name>
<age>12</age>
</level2>
<level2>
<name>John</name>
<age>23</age>
</level2>
</level1>
</doc>
When I perform some basic T_SQL
SELECT TOP 1
DocumentXML.query('data(//doc/name)'),
DocumentXML.query('data(//doc/age)')
FROM [DBNAME].[dbo].[TBLNAME]
I get
ID | Name | Age
----------------------
1 | JamesJohn | 1223
How do I re-write the T-SQL so it displays as
ID | Name | Age
--------------------
1 | James | 12
2 | John | 23

Your example doesn't work for me; the second level2 opens with </level2>. And //doc/name doesn't exist; might be //doc/level1/level2/name.
Here's an example of how to retrieve a rowset from an XML:
declare #t table (id int identity, doc xml)
insert #t (doc) values (
'<doc>
<level1>
<level2>
<name>James</name>
<age>12</age>
</level2>
<level2>
<name>John</name>
<age>23</age>
</level2>
</level1>
</doc>')
SELECT x.a.value('(name)[1]','varchar(50)') as col1
, x.a.value('(age)[1]','varchar(50)') as col2
FROM #t t
cross apply
t.doc.nodes('//level2') x(a)
This prints:
col1 col2
James 12
John 23

Related

SQL query XML and return null if node is not existing [duplicate]

This question already has answers here:
CROSS APPLY compared to OUTER APPLY
(2 answers)
Closed last year.
I have xml files where a node (field2) is not always present. If the node is not present i want to get null value.
SELECT
field1, field2
FROM
(SELECT DISTINCT
xmlField1.value('text()[1]','VARCHAR(256)') AS field1,
xmlField2.value('text()[1]','VARCHAR(256)') AS field2
FROM
[dbo].XMLTable t
CROSS APPLY
[XMLData].nodes('/collection/test/field1') A(xmlField1)
CROSS APPLY
[XMLData].nodes('/collection/test/field2') B(xmlField2)) xmlData
This query works if I have both fields in the XML file, but if field2 is missing, I don't get any values returned.
A minimal reproducible example is not provided.
Please try the following conceptual example.
SQL
-- DDL and sample data population, start
DECLARE #tbl TABLE (ID INT IDENTITY(1,1) PRIMARY KEY, xmldata XML);
INSERT INTO #tbl (xmldata) VALUES
(N'<collection>
<test>
<field1>fld11</field1>
<field2>fld12</field2>
</test>
<test>
<field1>fld12</field1>
</test>
<test>
<field1>fld13</field1>
<field2/>
</test>
</collection>');
-- DDL and sample data population, end
SELECT ID
, c.value('(field1/text())[1]','VARCHAR(256)') AS field1
, c.value('(field2/text())[1]','VARCHAR(256)') AS field2
FROM #tbl
CROSS APPLY xmldata.nodes('/collection/test') AS t(c);
Output
+----+--------+--------+
| ID | field1 | field2 |
+----+--------+--------+
| 1 | fld11 | fld12 |
| 1 | fld12 | NULL |
| 1 | fld13 | NULL |
+----+--------+--------+

How to parse xml data from a table and iterate each xml for showing inside perticular data

I have a table as following
table 1
=======
ID | XMLcol
----------------------------
1 <?xml version="...</users>
2 <?xml version="...</users>
In my each xml data in the XMLcol contains informations about severel users.
As a example firs row 1 contain three users. row 2 contains two users.
row 1 xml data
<?xml version="1.0"?>
<users>
<user>
<name>user1</name>
</user>
<user>
<name>user2</name>
</user>
<user>
<name>user3</name>
</user>
</users>
row 2 xml data
<?xml version="1.0"?>
<users>
<user>
<name>user4</name>
</user>
<user>
<name>user5</name>
</user>
</users>
I want to create a view by allow to repeating the ID and show the each user name in another column as follows.
so final view should be like this,
ID | name
----------------------------
1 user1
1 user2
1 user3
2 user4
2 user5
Is there anyway to do such a kind of thing?
Use an XMLTABLE:
SQL Fiddle
Oracle 11g R2 Schema Setup:
CREATE TABLE table1 ( id, xml ) AS
SELECT 1, '<?xml version="1.0"?>
<users>
<user><name>user1</name></user>
<user><name>user2</name></user>
<user><name>user3</name></user>
</users>' FROM DUAL UNION ALL
SELECT 2, '<?xml version="1.0"?>
<users>
<user><name>user4</name></user>
<user><name>user5</name></user>
</users>' FROM DUAL
Query 1:
SELECT t.id,
x.name
FROM table1 t
CROSS JOIN
XMLTABLE(
'/users/user'
PASSING XMLType( t.xml )
COLUMNS name VARCHAR2(200) PATH 'name'
) x
Results:
| ID | NAME |
|----|-------|
| 1 | user1 |
| 1 | user2 |
| 1 | user3 |
| 2 | user4 |
| 2 | user5 |

SQL query hierarchical XML with multiple sub-elements

I'm using Microsoft SQL server.
I have a simple hierarchy like a directional graph in Xml:
DECLARE #XML as XML = CAST(
'<ROOT>
<NODE NODE_ID="1">
<EDGE>2</EDGE>
<EDGE>3</EDGE>
<EDGE>4</EDGE>
</NODE>
<NODE NODE_ID="2">
<EDGE>1</EDGE>
<EDGE>3</EDGE>
</NODE>
</ROOT>' AS XML);
My desired output would be a table like this:
SOURCE_NODE_ID | DEST_NODE_ID
1 | 2
1 | 3
1 | 4
2 | 1
2 | 3
A query like this:
SELECT B.value('data(#NODE_ID)','int') AS SOURCE_NODE_ID,
A.B.value('(EDGE/text())[1]', 'int') AS DEST_NODE_ID
FROM #XML.nodes('/ROOT/NODE') AS A(B);
Only returns the first edge:
SOURCE_NODE_ID | DEST_NODE_ID
1 | 2
2 | 1
This one does a little better:
SELECT B.value('data(#NODE_ID)','int') AS SOURCE_NODE_ID,
B.query('EDGE').value('.', 'int') AS DEST_NODE_ID
FROM #XML.nodes('/ROOT/NODE') AS A(B);
Only it concatenates all edges into one cell:
SOURCE_NODE_ID | DEST_NODE_ID
1 | 234
2 | 13
How can I get my desired result? Should I join with an inner query or something? Probably I'm making it too complicated, surely there is a simple solution to this?
Try it like this
As there are many NODE elements, you need to call .nodes() for them. As there are many EDGE elements nested, you need to call CROSS APPLY .nodes() for them.
The rest is easy...
DECLARE #XML as XML = CAST(
'<ROOT>
<NODE NODE_ID="1">
<EDGE>2</EDGE>
<EDGE>3</EDGE>
<EDGE>4</EDGE>
</NODE>
<NODE NODE_ID="2">
<EDGE>1</EDGE>
<EDGE>3</EDGE>
</NODE>
</ROOT>' AS XML);
SELECT Nd.value('#NODE_ID','INT') AS SOURCE_NODE_ID
,Edg.value('.','INT') AS DEST_NODE_ID
FROM #XML.nodes('/ROOT/NODE') AS A(Nd)
CROSS APPLY A.Nd.nodes('EDGE') AS B(Edg)
The result
SOURCE_NODE_ID DEST_NODE_ID
1 2
1 3
1 4
2 1
2 3

SQL Server - Query The Data From XML File

I am new to XML stuff. I've figured out how to query and return the values from the XML file (example below). However, I run into a problem that it only capture the first node of 'SerialNo' tag because the tag has the same node name "SerialNo" repeated. In the XML file, it has 4 serial numbers for SKU#TT234343, but it only gives me the first Serial11111. I am totally stuck and don't know how to list all of those serial#.
I would like the query result for SKU#TT234343, listing all 4 serial numbers if possible.
Please help. Thanks!
The XML File looks like:
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<ROOT>
<ShipNotice version="1" >
<InvoiceDate>01/01/2015</InvoiceDate>
<InvoiceNumber>6868686</InvoiceNumber>
<ShipDate>02/02/2015</ShipDate>
<ShipTime>2306</ShipTime>
<PONumber>P444444</PONumber>
<PODate>03/03/2015</PODate>
<ShipCode>XXX</ShipCode>
<ShipDescription>FedEx Economy</ShipDescription>
<ShipTo>
<AddressName>ShipABC</AddressName>
<AddressContact>Name1</AddressContact>
<AddressLine1>2222 Street Name</AddressLine1>
<AddressLine2> </AddressLine2>
<City>AUSTIN</City>
<State>TX</State>
<ZipCode>78111</ZipCode>
</ShipTo>
<BillTo>
<AddressName>BillABC</AddressName>
<AddressContact>Name1</AddressContact>
<AddressLine1>1234 Street Name</AddressLine1>
<AddressLine2>-SUITE 111</AddressLine2>
<City>Los Angeles</City>
<State>CA</State>
<ZipCode>95136</ZipCode>
</BillTo>
<TotalWeight>324</TotalWeight>
<EmptyCartonWGT>0</EmptyCartonWGT>
<NumberOfCarton>1</NumberOfCarton>
<DirectShipFlag>D</DirectShipFlag>
<ShipFromWarehouse>88</ShipFromWarehouse>
<ShipFromZip>94538</ShipFromZip>
<ShipTrackNo>33333333</ShipTrackNo>
<EndUserPONumber>55555555</EndUserPONumber>
<CustomerSONumber/>
<Package sequence="1" >
<TrackNumber>666666666</TrackNumber>
<PackageWeight>324</PackageWeight>
<Item sequence="1" >
<SOLineNo>1</SOLineNo>
<MfgPN>XYZ1111111</MfgPN>
<SKU>TT234343</SKU>
<ShipQuantity>4</ShipQuantity>
<CustPOLineNo>1</CustPOLineNo>
<CustSOLineNo/>
<Description>Server1234</Description>
<CustPN/>
<UPC/>
<UnitPrice>1000</UnitPrice>
<EndUserPOLineNo>0</EndUserPOLineNo>
<SerialNo>Serial11111</SerialNo>
<SerialNo>Serial22222</SerialNo>
<SerialNo>Serial33333</SerialNo>
<SerialNo>Serial44444</SerialNo>
</Item>
<Item sequence="2" >
<SOLineNo>2</SOLineNo>
<MfgPN>XYZ222222</MfgPN>
<SKU>TT8848788</SKU>
<ShipQuantity>4</ShipQuantity>
<CustPOLineNo>2</CustPOLineNo>
<CustSOLineNo/>
<Description>GGG localization</Description>
<CustPN/>
<UPC/>
<UnitPrice>0.00</UnitPrice>
<EndUserPOLineNo>0</EndUserPOLineNo>
<SerialNo/>
</Item>
</Package>
</ShipNotice>
</ROOT>
The SQL Query:
DECLARE #XML AS XML, #hDoc AS INT, #SQL NVARCHAR (MAX)
EXEC sp_xml_preparedocument #hDoc OUTPUT, #xmlData
SELECT
InvoiceNumber, PONumber, PODate
, AddressName
, MfgPN, SerialNo
--, AddressContact, AddressLine1, AddressLine2, City, State, ZipCode
FROM OPENXML(#hDoc, '/ROOT/ShipNotice/Package/Item')
WITH
(
--- ################# Level 1 #################
InvoiceNumber [varchar](50) '../../InvoiceNumber',
PONumber [varchar](100) '../../PONumber',
PODate [varchar](100) '../../PODate',
--- ################# Level 2 #################
AddressName [varchar](100) '../../ShipTo/AddressName',
--- ################# Level 3 #################
MfgPN [varchar](100) 'MfgPN',
SerialNo [varchar](100) 'SerialNo'
)
You can try using the newer technology XQuery instead of OPENXML(). Using XQuery, you can use nodes() method to shred the XML on elements that will correspond to the rows in the output, and use value() to extract the element value :
SELECT
shipnotice.value('InvoiceNumber[1]','varchar(20)') InvoiceNumber
, shipnotice.value('PONumber[1]','varchar(20)') PONumber
, shipnotice.value('PODate[1]','varchar(20)') PODate
, shipnotice.value('(ShipTo/AddressName)[1]','varchar(100)') AddressName
, item.value('MfgPN[1]','varchar(100)') MfgPN
, serialno.value('.','varchar(100)') SerialNo
FROM #XML.nodes('/ROOT/ShipNotice') as t(shipnotice)
OUTER APPLY shipnotice.nodes('Package/Item') as t2(item)
OUTER APPLY item.nodes('SerialNo') as t3(serialno)
Sqlfiddle Demo
output :
| InvoiceNumber | PONumber | PODate | AddressName | MfgPN | SerialNo |
|---------------|----------|------------|-------------|------------|-------------|
| 6868686 | P444444 | 03/03/2015 | ShipABC | XYZ1111111 | Serial11111 |
| 6868686 | P444444 | 03/03/2015 | ShipABC | XYZ1111111 | Serial22222 |
| 6868686 | P444444 | 03/03/2015 | ShipABC | XYZ1111111 | Serial33333 |
| 6868686 | P444444 | 03/03/2015 | ShipABC | XYZ1111111 | Serial44444 |
| 6868686 | P444444 | 03/03/2015 | ShipABC | XYZ222222 | |

Query XML File uploaded to single column in SQL Server

I am trying to learn XQuery and Xpath in SQL Server
I created a sample file and uploaded it to a Table with 2 columns ID, XMLDoc. The below code is within the document in the XMLDoc column so it is the only record in the column.
I am trying to query the file so it will show all the results in a table like a normal select statement would. How would you construct the select statement to select all the information like a select * ? How would you select one field like all suppliers? I would like to select the supplier, requestor for each item.
Here is the xml:
<tst:Document xmlns:tst ="http://www.w3.org/2001/XMLSchema" SchemaVersion="0.1" Classification="Test" UniqueIdentifier="1234" Title="Test">
<tst:Revision RevNumber="0" TimeStamp="2013-01-21T12:56:00">
<tst:Author Name="Me" Guid="1234" />
</tst:Revision>
<tst:Formats>
<tst:A12 Item="1">
<tst:Requestor Name="ADC" />
<tst:Supplier Name="BBC" />
<tst:Code>B</tst:Code>
<tst:IsRequirement>true</tst:IsRequirement>
<tst:IsNotRequired>false</tst:IsInformation>
<tst:Remarks>ADC (Random Input Section)</tst:Remarks>
<tst:Notes>Next Round.</tst:Notes>
<tst:Events>
<tst:SubTest Item="0">
<tst:BLDG>BLDG1</tst:BLDG>
<tst:BLDG2>BLDG2</tst:BLDG2>
<tst:Function>Testing</tst:Function>
<tst:Desciption>Normal Flow</tst:Desciption>
</tst:SubTest>
</tst:Events>
<tst:IsReady>true</tst:IsReady>
<tst:IsNotReady>false</tst:IsNotReady>
</tst:A12>
<tst:A12 Item="2">
<tst:Requestor Name="ADC" />
<tst:Supplier Name="BBC" />
<tst:Code>A</tst:Code>
<tst:IsRequirement>true</tst:IsRequirement>
<tst:IsInformation>false</tst:IsInformation>
<tst:Remarks>Requirement Not yet met.</tst:Remarks>
<tst:Notes>Ready.</tst:Notes>
<tst:Events>
<tst:SubTest Item="0">
<tst:BLDG>BLDG3</tst:BLDG>
<tst:BLDG2>BLDG4</tst:BLDG2>
<tst:TotalEvents>1</tst:TotalEvents>
<tst:Function>Development</tst:Function>
<tst:Desciption>Process Flow</tst:Desciption>
</tst:SubTest>
</tst:Events>
<tst:IsReady>true</tst:IsReady>
<tst:IsNotReady>false</tst:IsNotReady>
</tst:A12>
</tst:Formats>
</tst:Document>
Query I ran
I just got a return, but it is still showing it in xml form:
Select XMLDoc.query('/*/*/*/*[local-name()=("Requestor", "Supplier")]')
From XMLLoad
I Updated the xml snippet, sry had a typo! It will load now
INSERT INTO TableName(ColumnName)
SELECT * FROM OPENROWSET(
BULK 'C:\Users\Filepath.xml',
SINGLE_BLOB) AS x;
SQL Fiddle
MS SQL Server 2008 Schema Setup:
create table XMLDoc (XMLLoad xml);
insert into XMLDoc(XMLLoad) values('
<tst:Document xmlns:tst ="http://www.w3.org/2001/XMLSchema" SchemaVersion="0.1" Classification="Test" UniqueIdentifier="1234" Title="Test">
<tst:Revision RevNumber="0" TimeStamp="2013-01-21T12:56:00">
<tst:Author Name="Me" Guid="1234" />
</tst:Revision>
<tst:Formats>
<tst:A12 Item="1">
<tst:Requestor Name="ADC" />
<tst:Supplier Name="BBC" />
<tst:Code>B</tst:Code>
<tst:IsRequirement>true</tst:IsRequirement>
<tst:IsInformation>false</tst:IsInformation>
<tst:Remarks>ADC (Random Input Section)</tst:Remarks>
<tst:Notes>Next Round.</tst:Notes>
<tst:Events>
<tst:SubTest Item="0">
<tst:BLDG>BLDG1</tst:BLDG>
<tst:BLDG2>BLDG2</tst:BLDG2>
<tst:Function>Testing</tst:Function>
<tst:Desciption>Normal Flow</tst:Desciption>
</tst:SubTest>
</tst:Events>
<tst:IsReady>true</tst:IsReady>
<tst:IsNotReady>false</tst:IsNotReady>
</tst:A12>
<tst:A12 Item="2">
<tst:Requestor Name="ADC" />
<tst:Supplier Name="BBC" />
<tst:Code>A</tst:Code>
<tst:IsRequirement>true</tst:IsRequirement>
<tst:IsInformation>false</tst:IsInformation>
<tst:Remarks>Requirement Not yet met.</tst:Remarks>
<tst:Notes>Ready.</tst:Notes>
<tst:Events>
<tst:SubTest Item="0">
<tst:BLDG>BLDG3</tst:BLDG>
<tst:BLDG2>BLDG4</tst:BLDG2>
<tst:TotalEvents>1</tst:TotalEvents>
<tst:Function>Development</tst:Function>
<tst:Desciption>Process Flow</tst:Desciption>
</tst:SubTest>
</tst:Events>
<tst:IsReady>true</tst:IsReady>
<tst:IsNotReady>false</tst:IsNotReady>
</tst:A12>
</tst:Formats>
</tst:Document>');
Query 1:
with xmlnamespaces('http://www.w3.org/2001/XMLSchema' as tst)
select A12.X.value('#Item', 'int') as A12,
A12.X.value('tst:Requestor[1]/#Name', 'varchar(25)') as Requestor,
A12.X.value('tst:Supplier[1]/#Name', 'varchar(25)') as Supplier,
A12.X.value('(tst:Code/text())[1]', 'varchar(25)') as Code,
A12.X.value('(tst:IsRequirement/text())[1]', 'bit') as IsRequirement,
A12.X.value('(tst:IsInformation/text())[1]', 'bit') as IsInformation,
A12.X.value('(tst:Remarks/text())[1]', 'varchar(50)') as Remarks,
A12.X.value('(tst:Notes/text())[1]', 'varchar(50)') as Notes,
ST.X.value('#Item', 'int') as SubTest,
ST.X.value('(tst:BLDG/text())[1]', 'varchar(25)') as BLDG,
ST.X.value('(tst:BLDG2/text())[1]', 'varchar(25)') as BLDG2,
ST.X.value('(tst:TotalEvents/text())[1]', 'int') as TotalEvents,
ST.X.value('(tst:Function/text())[1]', 'varchar(25)') as [Function],
ST.X.value('(tst:Desciption/text())[1]', 'varchar(50)') as Desciption
from XMLDoc as X
cross apply X.XMLLoad.nodes('/tst:Document/tst:Formats/tst:A12') as A12(X)
cross apply A12.X.nodes('tst:Events/tst:SubTest') as ST(X)
Results:
| A12 | REQUESTOR | SUPPLIER | CODE | ISREQUIREMENT | ISINFORMATION | REMARKS | NOTES | SUBTEST | BLDG | BLDG2 | TOTALEVENTS | FUNCTION | DESCIPTION |
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| 1 | ADC | BBC | B | 1 | 0 | ADC (Random Input Section) | Next Round. | 0 | BLDG1 | BLDG2 | (null) | Testing | Normal Flow |
| 2 | ADC | BBC | A | 1 | 0 | Requirement Not yet met. | Ready. | 0 | BLDG3 | BLDG4 | 1 | Development | Process Flow |
Check out value() and nodes().