Need help to format output of SQL Server XML sibling query - sql-server

Consider the following SQL Server XML output:
<CUSTOMER>
<CUST_ID>TEST_CUSTOMER_01</CUST_ID>
<ORG_CODE>MY_ORG</ORG_CODE>
<CUSTOMER_TYPE CUST_TYPE="RETAIL" />
<CUSTOMER_COUNTRY CTRY_CODE="US" />
</CUSTOMER>
It was generated by the following SQL statement.
SELECT
CUSTOMER.CUST_ID, CUSTOMER.ORG_CODE,
(SELECT CUSTOMER_TYPE.CUST_TYPE
FROM CUSTOMER_TYPE
WHERE CUSTOMER.CUST_ID = CUSTOMER_TYPE.CUSTOMER_ID
FOR XML AUTO, TYPE),
(SELECT CUSTOMER_COUNTRY.CTRY_CODE
FROM CUSTOMER_COUNTRY
WHERE CUSTOMER.CUST_ID = CUSTOMER_COUNTRY.CUSTOMER_ID
FOR XML AUTO, TYPE)
FROM
CUSTOMER
WHERE
CUSTOMER.CUST_ID = 'TEST_CUSTOMER_01'
FOR XML AUTO, ELEMENTS
GO
It's required that the output look like the output below. Substituting ELEMENTS for the two TYPE words in the query above doesn't do it.
How then do I do it?
<CUSTOMER>
<CUST_ID>TEST_CUSTOMER_01</CUST_ID>
<ORG_CODE>MY_ORG</ORG_CODE>
<CUSTOMER_TYPE>
<CUST_TYPE>SHIP_TO</CUST_TYPE>
</CUSTOMER_TYPE>
<CUSTOMER_COUNTRY>
<CTRY_CODE>US</CTRY_CODE>
</CUSTOMER_COUNTRY>
</CUSTOMER>
Thanks!

The best (best in usage and performance!) is FOR XML PATH. It is very intuitive and easy to define any output you want simply by naming them.
SELECT
'TEST_CUSTOMER_01' AS [CUST_ID]
,'MY_ORG' AS [ORG_CODE]
,'SHIP_TO' AS [CUSTOMER_TYPE/CUST_TYPE]
,'US' AS [CUSTOMER_COUNTRY/CTRY_CODE]
--FROM
-- CUSTOMER
--WHERE
-- CUSTOMER.CUST_ID = 'TEST_CUSTOMER_01'
FOR XML PATH('CUSTOMER')

Try this query.
select CUST_ID,ORG_CODE,( SELECT CUSTOMER_TYPE.CUST_TYPE AS CUST_TYPE
FROM #customer_type CUSTOMER_TYPE
WHERE CUSTOMER.CUST_ID = CUSTOMER_TYPE.CUSTOMER_ID
FOR XML path (''),TYPE) AS 'CUSTOMER_TYPE' ,(
SELECT CUSTOMER_COUNTRY.CTRY_CODE as CTRY_CODE
FROM #customer_country CUSTOMER_COUNTRY
WHERE CUSTOMER.CUST_ID = CUSTOMER_COUNTRY.CUSTOMER_ID
for xml path (''),TYPE
) AS 'CUSTOMER_COUNTRY' from
#customer CUSTOMER
for xml auto, ELEMENTS
Using the above query you will get the result as
<CUSTOMER>
<CUST_ID>TEST_CUSTOMER_01</CUST_ID>
<ORG_CODE>MY_ORG</ORG_CODE>
<CUSTOMER_TYPE>
<CUST_TYPE>SHIP_TO</CUST_TYPE>
</CUSTOMER_TYPE>
<CUSTOMER_COUNTRY>
<CTRY_CODE>US</CTRY_CODE>
</CUSTOMER_COUNTRY>
</CUSTOMER>

Related

SQL query to retrieve XML data

I have some XML in SQL Server:
Code to retrieve:
declare #xmlresponse xml
select top 1 #xmlrespone = xmlresponse from dto.t
;with xmlnamespaces(default 'http://www3')
select inputRefId = Node.Data.Value('.', 'varchar(50)')
from #xmlresponse.nodes('.') Node(Data)
This returns both fields (inputrefid and crn) as one string.
I would like to retrieve the values in separate fields starting with the inputrefid, but no matter what I try I get NULL.
e.g
select inputRefId = Node.Data.Value('(/inputRefId)[1]', 'varchar(50)')
Try it with this XQuery:
;WITH xmlnamespaces('http://www3' AS ns)
SELECT
inputRefId = Data.value('(ns:inputRefId)[1]', 'varchar(50)'),
crn = Data.value('(ns:crn)[1]', 'varchar(50)')
FROM
#xmlresponse.nodes('/resultDTO') Node(Data)
The point is that your top-level node - <resultDTO> does not have the http://www3 XML namespace - so you cannot really use the http://www3 as the default XML namespace for all the nodes in the XML - you need to be more specific and only apply it where it's really been set.

SQL Server parse XML to table - multiple node with the same name

I would like to parse XML into a table in SQL Server 2012 where my XML has nodes with the same name.
My SQL query which return only the first row:
SELECT
[date] = Node.Data.value('(date)[1]', 'NVARCHAR(MAX)'),
name = Node.Data.value('(name)[1]', 'VARCHAR(MAX)')
FROM
#xml.nodes('result/subject') Node(Data)
XML sample
<result>
<subject>
<date>2019-06-03</date>
<name>AZGREX</name>
<name>ABGDFC</name>
<name>WWGDFW</name>
<name>FDSFSD</name>
<name>FSDWEW</name>
<name>CXZCXZ</name>
<name>GWGRE</name>
</subject>
</result>
You need to use nodes in the FROM:
DECLARE #XML xml = '<result>
<subject>
<date>2019-06-03</date>
<name>AZGREX</name>
<name>ABGDFC</name>
<name>WWGDFW</name>
<name>FDSFSD</name>
<name>FSDWEW</name>
<name>CXZCXZ</name>
<name>GWGRE</name>
</subject>
</result>';
SELECT r.[subject].value('(date/text())[1]','date') AS [date],
s.[name].value('(./text())[1]','varchar(6)') AS [name] --obviously, you'll likely need a larger length
FROM (VALUES(#XML))V(X)
CROSS APPLY V.X.nodes('result/subject') r([subject])
CROSS APPLY r.[subject].nodes('name') s([name]);

Nested sub tag resultset xml T-SQL

I'm not an expert for XML query... but I need only little step to my goal.
With the query below.
I got a problem in EANs tag with the sub tag EAN.
SELECT
ExternalId,
[Name],
[Description],
BrandExternalId,
CategoryExternalId,
ProductPageUrl,
ImageUrl,
(SELECT ManufacturerPartNumber
FOR XML PATH('ManufacturerPartNumbers'), TYPE),
(SELECT b.EAN_Single as EAN
FROM #SP b
WHERE (ff.ExternalId = b.codart)
FOR XML PATH('EANs'), TYPE)
FROM
Cestino.acap.Bazaar_Servizio_00 ff with (nolock)
WHERE
[ExternalId] IN (100001023)
FOR XML PATH ('Product'), ROOT('Products');
I get this result:
<Products>
<Product>
<ExternalId>100001023</ExternalId>
<Name>Carta Lucida Adesiva Photo Stickers PS-101</Name>
<Description>Carta lucida Photo Stickers.</Description>
<BrandExternalId>CANON</BrandExternalId>
<CategoryExternalId>10132</CategoryExternalId>
<ManufacturerPartNumbers>
<ManufacturerPartNumber>0001C001</ManufacturerPartNumber>
</ManufacturerPartNumbers>
<EANs>
<EAN>0138030471030</EAN>
</EANs>
<EANs>
<EAN>5051749491517</EAN>
</EANs>
</Product>
</Products>
but I need the result to look like this:
<EANs>
<EAN>0138030471030</EAN>
<EAN>5051749491517</EAN>
</EANs>
Can someone help me with this?
THANKS Alen, Italy
Try this as the subquery.
(SELECT b.EAN_Single as EAN
FROM #SP b
WHERE (ff.ExternalId = b.codart)
FOR XML PATH(''), ROOT('EANS'), TYPE)

Combine and modify XML in TSQL

Using SQL Server 2005, is it possible to combine XML and add an attribute at same time?
Unfortunately, due to project restrictions, I need a SQL Server 2005 solution.
Consider the following, where I need to combine XML from multiple rows within a new <root> element...
; WITH [TestTable] AS (
SELECT 7 AS [PkId], CAST('<data><id>11</id><id>12</id></data>' AS XML) AS [Data]
UNION ALL
SELECT 12, CAST('<data><id>22</id></data>' AS XML)
UNION ALL
SELECT 43, CAST('<data><id>33</id></data>' AS XML)
)
SELECT (
SELECT XMLDATA as [*]
FROM (
SELECT [Data] AS [*]
FROM [TestTable]
FOR XML PATH(''), TYPE
) AS DATA(XMLDATA)
FOR XML PATH('root')
)
This produces the desired output of...
<root>
<data><id>11</id><id>12</id></data>
<data><id>22</id></data>
<data><id>33</id></data>
</root>
But what I need to do, if possible, is add an attribute to the existing data element in each of the rows with the PkId value. The desired output would then look like this...
<root>
<data pkid="7"><id>11</id><id>12</id></data>
<data pkid="12"><id>22</id></data>
<data pkid="43"><id>33</id></data>
</root>
My gut feeling is that this is going to be impossible without the use of a cursor, but if anybody knows a way of doing it I'd love to hear it.
At the request of #MattA, here is an example of some random data in the table...
[PkId] [UserId] [SubmittedDate] [Data]
1 1 2015-03-24 12:34:56 '<data><id>1</id><id>2</id></data>'
2 1 2015-03-23 09:15:52 '<data><id>3</id></data>'
3 2 2015-03-22 16:01:23 '<data><id>4</id><id>5</id></data>'
4 1 2015-03-21 13:45:34 '<data><id>6</id></data>'
Please note, that to make the question easier, I stated that I needed the PkId column as the attribute to the data. This is not actually the case - instead I need the [SubmittedDate] column to be used. I apologise if this caused confusion.
Using UserId=1 as a filter, the XML I would like from the above would be...
<root>
<data submitteddate="2015-03-24T12:34:56"><id>1</id><id>2</id></data>
<data submitteddate="2015-03-23T09:15:52"><id>3</id></data>
<data submitteddate="2015-03-21T13:45:34"><id>6</id></data>
</root>
The date would be formatted using the 126 date format available from CONVERT
Here's the quick answer for you. XML does support "modify", but shredding on a small data set like this works quite well too.
Code
--The existing XML
DECLARE #XML XML = '<root>
<data><id>11</id></data>
<data><id>22</id></data>
<data><id>33</id></data>
</root>'
--XML Shredded Back to a table
;WITH
ShreddedXML AS (
SELECT
ID = FieldAlias.value('(id)[1]','int')
FROM
#XML.nodes('/root/data') AS TableAlias(FieldAlias)
), ArbitraryPKGenerator AS (
SELECT CURRENT_TIMESTAMP AS PKid,
ID
FROM ShreddedXML
)
SELECT A.PKId AS "#PKid",
A.ID AS "id"
FROM ArbitraryPKGenerator AS A
FOR XML PATH('data'), ROOT('root')
And the XML
<root>
<data PKid="2015-03-24T09:44:55.770">
<id>11</id>
</data>
<data PKid="2015-03-24T09:44:55.770">
<id>22</id>
</data>
<data PKid="2015-03-24T09:44:55.770">
<id>33</id>
</data>
</root>

Parsing XML with XMLNS in SQL Server 2008 R2

I'm fairly new to querying XML datatypes. We receive XMLs from partners and one such partner sends us XMLs like this:
DECLARE #ResultData XML = '<outGoing xmlns="urn:testsystems-com:HH.2015.Services.Telephony.OutGoing">
<customer>
<ID>158</ID>
</customer>
</outGoing>'
In this example, I would like to pull only the ID out of the XML, but it seems the xmlns is preventing me from getting anything inside the XML:
SELECT cust.value('(ID)[1]', 'VARCHAR(40)') as 'CustomerID'
FROM #ResultData.nodes('/outGoing/customer') as t(cust)
returns NUll, but if I manually remove the XMLNS from the XML I get 158.
I've experimented with WITH XMLNAMESPACES to see if I could use that, but I'm obviously missing something. Since these XMLs will be coming in automatically, I would like to be able to parse the XML, but right now I'm stuck.
That should work:
DECLARE #ResultData XML = '<outGoing xmlns="urn:testsystems-com:HH.2015.Services.Telephony.OutGoing">
<customer>
<ID>158</ID>
</customer>
</outGoing>'
;WITH XMLNAMESPACES(DEFAULT 'urn:testsystems-com:HH.2015.Services.Telephony.OutGoing')
SELECT
#ResultData.value('(/outGoing/customer/ID)[1]', 'int')
or to use your approach:
;WITH XMLNAMESPACES(DEFAULT 'urn:testsystems-com:HH.2015.Services.Telephony.OutGoing')
SELECT
CustomerID = cust.value('(ID)[1]', 'INT')
FROM
#ResultData.nodes('/outGoing/customer') as t(cust)
This will return 158 as its value.
I've used WITH XMLNAMESPACES(DEFAULT .....) since this is the only XML namespace in play, and it's defined at the top-level node - so it applies to every node in the XML structure.

Resources