nested element FOR XML in SQL Server - sql-server

I'm trying to create XML from SQL Server and I'm stuck with nested elements. I try different FOR XML parameters but still cannot get the correct results.
query looks like this:
SELECT
Product.ID, Product.ProductName,
(SELECT
Images.ProductImage AS image
FROM Images
WHERE Images.ProductID = Product.ID
FOR XML PATH ('image_list'), ELEMENTS, TYPE
)
FROM (SELECT DISTINCT ID, ProductName FROM Product) Product
FOR XML PATH ('products'), ELEMENTS, root ('Root')
and I want get this XML like this:
<Root>
<products>
<ID>1</ID>
<ProductName>product 1</ProductName>
<image_list>
<image>picture1.jpg</image>
<image>picture2.jpg</image>
<image>picture3.jpg</image>
</image_list>
</products>
<products>
<ID>2</ID>
<ProductName>product 2</ProductName>
<image_list>
<image>picture1.jpg</image>
<image>picture2.jpg</image>
</image_list>
</products>
</Root>
First part is OK, the image_list is a problem. Any advice?

I solved :) ..probably is good to post a qustion, after that brain starts to work :)
I add AS 'image_list' under subquery, remove ELEMENTS and PATH name.
And that's it.
SELECT
Product.ID, Product.ProductName,
(SELECT
Images.ProductImage AS image
FROM Images
WHERE Images.ProductID = Product.ID
FOR XML PATH (''), TYPE
) 'image_list'
FROM (SELECT DISTINCT ID, ProductName FROM Product) Product
FOR XML PATH ('products'), ELEMENTS, root ('Root')
Results is:
<Root>
<products>
<ID>1</ID>
<ProductName>product 1 </ProductName>
<image_list>
<image>picture1.jpg</image>
<image>picture2.jpg</image>
<image>picture3.jpg</image>
</image_list>
</products>
<products>
<ID>2</ID>
<ProductName>product 2 </ProductName>
<image_list>
<image>picture1.jpg</image>
<image>picture2.jpg</image>
</image_list>
</products>
</Root>

Related

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)

Convert XML from one format to another

I have this below xml data which is stored in a table.
The XML Structure I have
<Response>
<Question ID="1">
<Value ID="1">I want a completely natural childbirth - no medical interventions for me</Value>
<Value ID="2">no medical interventions for me</Value>
</Question>
</Response>
I need to convert this XML to a slightly different format, like the below one.
The XML Structure I need
<Response>
<Question ID="1">
<SelectedChoices>
<Choice>
<ID>1</ID>
</Choice>
<Choice>
<ID>2</ID>
</Choice>
</SelectedChoices>
</Question>
</Response>
Here the "Value" is changed to "Choice" and "ID" attribute of "Value" element is changed to an element.
I know this can be done in other ways, like using an XSLT. But it will be much more helpful if can accomplish with SQL itself.
Can someone help me to convert this using SQL?
Use this variable to test the statements
DECLARE #xml XML=
N'<Response>
<Question ID="1">
<Value ID="1">I want a completely natural childbirth - no medical interventions for me</Value>
<Value ID="2">no medical interventions for me</Value>
</Question>
</Response>';
This can be done with FLWOR-XQuery:
The query will re-build the XML out of itself... Very similar to XSLT...
SELECT #xml.query(
N'
<Response>
{
for $q in /Response/Question
return
<Question ID="{$q/#ID}">
<SelectedChoices>
{
for $v in $q/Value
return <Choice><ID>{string($v/#ID)}</ID></Choice>
}
</SelectedChoices>
</Question>
}
</Response>
'
);
Another approach: Shredding and re-build
You'd reach the same with this, but I'd prefere the first...
WITH Shredded AS
(
SELECT q.value('#ID','int') AS qID
,v.value('#ID','int') AS vID
FROM #xml.nodes('/Response/Question') AS A(q)
OUTER APPLY q.nodes('Value') AS B(v)
)
SELECT t1.qID AS [#ID]
,(
SELECT t2.vID AS ID
FROM Shredded AS t2
WHERE t1.qID=t2.qID
FOR XML PATH('Choice'),ROOT('SelectedChoices'),TYPE
) AS [node()]
FROM Shredded AS t1
GROUP BY t1.qID
FOR XML PATH('Question'),ROOT('Response')

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>

sql server 2008 - import data into existing tables from XML files

Before data is removed from an sql server database, it is exported and saved as an XML file in the event that this data is to be recovered at a later stage. I am now trying to get the data back into the database from an XML file but cannot find the best way to do this. The SQL server import / export wizard does not appear to support XML. I have looked at the XML Bulk Load component but this doesn't look like it would work for my issue. Has anyone any suggestions?
The XML may look like below and I woud want each row inserting:
<?xml version="1.0" encoding="UTF-8"?>
<products>
<product>
<prod_id>4235823</prod_id>
<productImageURL>image1.jpg</productImageURL>
<entryDate>Aug 30 2011 01:47:08:317PM</entryDate>
<category>859191</category>
<productDescription>product description 1</productDescription>
<productName>product name 1</productName>
<Price>9.99</Price>
</product>
<product>
<prod_id>8989595</prod_id>
<productImageURL>image2.jpg</productImageURL>
<entryDate>Aug 30 2011 01:47:08:317PM</entryDate>
<category>859191</category>
<productDescription>product description 2</productDescription>
<productName>product name 2</productName>
<Price>2.99</Price>
</product>
<product>
<prod_id>4575454</prod_id>
<productImageURL>image3.jpg</productImageURL>
<entryDate>Aug 30 2011 01:47:08:317PM</entryDate>
<category>859191</category>
<productDescription>product description 3</productDescription>
<productName>product name 3</productName>
<Price>5.99</Price>
</product>
</products>
SELECT
p.value('prod_id[1]','INT'),
p.value('productImageURL[1]','VARCHAR(100)'),
p.value('category[1]','VARCHAR(100)'),
p.value('productDescription[1]','VARCHAR(1000)'),
p.value('productName[1]','VARCHAR(100)'),
p.value('Price[1]','money'),
FROM #xmlfile.nodes('/Products/Product') as Product(p)
After a bit of research I found I needed the following:
DECLARE #xml xml
SET #xml = N'<Products>
<Product>
<id>4</id>
<name>Amy</name>
<age>25</age>
</Product>
<Product>
<id>7</id>
<name>Vicky</name>
<age>40</age>
</Product>
</Products>'
INSERT INTO dbo.leanne_test (id, name, age)
SELECT
doc.col.value('id[1]', 'nvarchar(10)') id
,doc.col.value('name[1]', 'varchar(100)') name
,doc.col.value('age[1]', 'nvarchar(10)') age
FROM #xml.nodes('/Products/Product') doc(col)

Microsoft SQL Server xml data

This site has a technique to pass xml data around in Microsoft SQL Server:
DECLARE #productIds xml
SET #productIds ='<Products><id>3</id><id>6</id><id>15</id></Products>'
SELECT
ParamValues.ID.value('.','VARCHAR(20)')
FROM #productIds.nodes('/Products/id') as ParamValues(ID)
But what is the syntax if I add another field?
The following does NOT work:
DECLARE #productIds xml
SET #productIds ='<Products><id>3</id><descr>Three</descr><id>6</id><descr>six</descr><id>15</id><descr>Fifteen</descr></Products>'
SELECT
ParamValues.ID.value('.','VARCHAR(20)')
,ParamValues.descr.value('.','VARCHAR(20)')
FROM #productIds.nodes('/Products/id') as ParamValues(ID)
Note: Maybe I've constructed my xml wrong.
You need to use something like:
SELECT
ParamValues.ID.value('(id)[1]','VARCHAR(20)'),
ParamValues.ID.value('(descr)[1]','VARCHAR(20)')
FROM
#productIds.nodes('/Products') as ParamValues(ID)
That FROM statement there defines something like a "virtual table" called ParamValues.ID - you need to select the <Products> node into that virtual table and then access the properties inside it.
Furthermore, your XML structure is very badly chosen:
<Products>
<id>3</id>
<descr>Three</descr>
<id>6</id>
<descr>six</descr>
<id>15</id>
<descr>Fifteen</descr>
</Products>
You won't be able to select the individual pairs of id/descr - you should use something more like:
<Products>
<Product>
<id>3</id>
<descr>Three</descr>
</Product>
<Product>
<id>6</id>
<descr>six</descr>
</Product>
<Product>
<id>15</id>
<descr>Fifteen</descr>
</Product>
</Products>
Then you could retrieve all items using this SQL XML query:
SELECT
ParamValues.ID.value('(id)[1]','VARCHAR(20)') AS 'ID',
ParamValues.ID.value('(descr)[1]','VARCHAR(20)') AS 'Description'
FROM
#productIds.nodes('/Products/Product') as ParamValues(ID)
ID Descrition
3 Three
6 six
15 Fifteen
You must wrap each set of id and descr into one parent node. Say Row. Now you can access each pair like this.
DECLARE #productIds xml
SET #productIds ='<Products><Row><id>3</id><descr>Three</descr></Row><Row><id>6</id><descr>six</descr></Row><Row><id>15</id><descr>Fifteen</descr></Row></Products>'
SELECT
ParamValues.Row.query('id').value('.','VARCHAR(20)'),
ParamValues.Row.query('descr').value('.','VARCHAR(20)')
FROM #productIds.nodes('/Products/Row') as ParamValues(Row)

Resources