Using MS SQL Server, I've got some data in an XML field (called XML), which is structured like this:
<Transaction01>
<TransactionSetPurpose>Insert</TransactionSetPurpose>
<POHeader>
<PO_NBR>LG40016181</PO_NBR>
</POHeader>
</Transaction01>
I'm trying to create a SQL query to fetch another column called SubmittedDate, along with the PO_NBR from this XML field. Being new to XPath, I've read numerous examples and tried both query and value, but I've not been successful yet. For example:
SELECT SubmittedDate,
XML.query('data(/POHeader/PO_NBR)') as PO_NBR
FROM SubmitXML
This just gives me a empty column. After getting a working test from Quassnoi, I worked from his XML to mine, and discovered the problem is the xmlns and xmlns:i attributes in the root node:
<Transaction01 xmlns="http://services.iesltd.com/" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
So how do I get around that?
A.The value() method retrieves the ProductID attribute value from the XML. The value is then assigned to an int variable. Value 1 is returned as a result.
To retrieve data in XML format from SQL Server database, we can use FOR XML <options> clause. Notice the last three words in the above query. We have a normal SELECT statement and in the last of the statement, we are suffixing FOR XML RAW that will return the data from PersonalDetails table in Raw xml format.
XML data can be queried using an SQL fullselect or with the SQL/XML query functions of XMLQUERY and XMLTABLE. The XMLEXISTS predicate can also be used in SQL queries on XML data.
SELECT SubmittedDate,
XML.query('data(/Transaction01/POHeader/PO_NBR)') as PO_NBR
FROM SubmitXML
You original XPath
, /POHeader/PO_NBR
, assumed that POHeader
is the root node (which is not).
A sample query to check:
DECLARE @myxml XML
SET @myxml = '
<Transaction01>
<TransactionSetPurpose>Insert</TransactionSetPurpose>
<POHeader>
<PO_NBR>LG40016181</PO_NBR>
</POHeader>
</Transaction01>'
SELECT @myxml.query('data(/Transaction01/POHeader/PO_NBR)')
If Transaction01
is not always the root node (which is not a good thing), use this:
SELECT SubmittedDate,
XML.query('data(/*/POHeader/PO_NBR)') as PO_NBR
FROM SubmitXML
Generally, XML
schema assumes that the tag names are fixed and the variable parts go to the data of the nodes and the attributes rather than into their names, like this:
<Transaction id='01'>
<TransactionSetPurpose>Insert</TransactionSetPurpose>
<POHeader>
<PO_NBR>LG40016181</PO_NBR>
</POHeader>
</Transaction>
Update:
You should declare the namespaces using WITH XMLNAMESPACES
:
DECLARE @myxml XML
SET @myxml = '
<Transaction01 xmlns="http://services.iesltd.com/" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<TransactionSetPurpose>Insert</TransactionSetPurpose>
<POHeader>
<PO_NBR>LG40016181</PO_NBR>
</POHeader>
</Transaction01>'
;
WITH XMLNAMESPACES
(
'http://services.iesltd.com/' AS m
)
SELECT @myxml.query
(
'data(/*/m:POHeader/m:PO_NBR)'
)
Update 2:
To sort:
;
WITH XMLNAMESPACES
(
'http://services.iesltd.com/' AS m
)
SELECT SubmittedDate,
XML.value('(/*/m:POHeader/m:PO_NBR)[1]', 'NVARCHAR(200)') AS po_nbr
FROM SubmitXML
ORDER BY
po_nbr
If you want to avoid hardcoding Transaction01, you can try this:
SELECT SubmittedDate,
XML.query('data(//POHeader/PO_NBR)') as PO_NBR
FROM SubmitXML
E.G:
CREATE TABLE #TEMP (XMLTEXT XML)
INSERT INTO #TEMP
SELECT '<Transaction01> <TransactionSetPurpose>Insert</TransactionSetPurpose> <POHeader> <PO_NBR>LG40016181</PO_NBR> </POHeader> </Transaction01> '
SELECT XMLTEXT.query('data(//POHeader/PO_NBR)') as PO_NBR
FROM #TEMP
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With