Nested FOR XML results with SQL Server’s PATH mode - sql-server

I am creating an SSIS package where I am pulling data from a table and need to transform it to an XML file using these columns:
select
iqr_FirstName AS FIRSTNAME,
iqr_LastName AS LASTNAME,
iqr_Employer AS EMPLOYER,
iqr_Occupation AS OCCUPATION,
iqr_Line1 AS ADR1,
iqr_City AS CITY, iqr_State AS State,
iqr_Zip AS ZIP,
iqr_CCAmount AS AMOUNT, iqr_CreatedOn AS DATE
from
std7_ImportQueueRecord
for xml path('Individual')
My issue with nesting is I need separated nodes for the following template:
<?xml version="1.0" encoding="UTF-8"?>
<DATABASE name="cc_Sample">
<INDIVIDUAL>
<LASTNAME>last</LASTNAME>
<FIRSTNAME>first</FIRSTNAME>
<MIDDLE></MIDDLE>
<NAMETITLE></NAMETITLE>
<NAMESUFFIX></NAMESUFFIX>
<BIRTHDATE></BIRTHDATE>
<OCCUPATION></OCCUPATION>
<EMPLOYER>company</EMPLOYER>
<SALUTATION>first</SALUTATION>
<GENDER></GENDER>
<ADDRESS>
<DESCR>3</DESCR>
<COMPANY></COMPANY>
<ADR1>adr1</ADR1>
<ADR2>adr2</ADR2>
<CITY>city</CITY>
<STATE>st</STATE>
<ZIP>zip</ZIP>
</ADDRESS>
<PHONENUMBER>
<USES>1</USES>
<PHONE>111-1111</PHONE>
<AREA>111</AREA>
<EXT></EXT>
</PHONENUMBER>
<PHONENUMBER>
<USES>2</USES>
<PHONE>222-2222</PHONE>
<AREA>222</AREA>
<EXT></EXT>
</PHONENUMBER>
<PHONENUMBER>
<USES>3</USES>
<PHONE>333-3333</PHONE>
<AREA>333</AREA>
<EXT></EXT>
</PHONENUMBER>
<EMAILADDRESS>
<EMAIL>test#test.com</EMAIL>
</EMAILADDRESS>
<CODE>
<ID>2</ID>
<DATE>2005-05-17</DATE>
<MEMO></MEMO>
</CODE>
<CODE>
<ID>3</ID>
<DATE>2005-05-17</DATE>
<MEMO></MEMO>
</CODE>
<COMMUNICATION>
<ID>6</ID>
<DATE>2005-05-17</DATE>
<MEMO></MEMO>
<TEXTAREA>details go here</TEXTAREA>
</COMMUNICATION>
<FINANCIAL>
<TYPE>contribution</TYPE>
<AMOUNT>150</AMOUNT>
<DATE>2005-05-17</DATE>
<CATEGORYID>3</CATEGORYID>
<THANKED>0</THANKED>
<CHECKNUMBER>Credit Card</CHECKNUMBER>
<MEMO></MEMO>
<CARDTYPE>VISA</CARDTYPE>
<CARDNUMBER>4444-4444-4444-4444</CARDNUMBER>
<CVV2>987</CVV2>
<EXPMONTH>02</EXPMONTH>
<EXPYEAR>2012</EXPYEAR>
</FINANCIAL>
</INDIVIDUAL>
</DATABASE>
I am not finding how to query multiple nodes as in my example.

You can try using this:
select
iqr_FirstName AS FIRSTNAME,
iqr_LastName AS LASTNAME,
iqr_Employer AS EMPLOYER,
iqr_Occupation AS OCCUPATION,
iqr_Line1 AS 'ADDRESS/ADR1',
iqr_City AS 'ADDRESS/CITY',
iqr_State AS 'ADDRESS/State',
iqr_Zip AS 'ADDRESS/ZIP',
iqr_CCAmount AS AMOUNT,
iqr_CreatedOn AS DATE
from
std7_ImportQueueRecord
for xml path('Individual')
to add extra structure (and XML elements) to your generated XML

Related

Insert XML child node to SQL table

I've got an XML file like this and I'm working with SQL 2014 SP2
<?xml version='1.0' encoding='UTF-8'?>
<gwl>
<version>123456789</version>
<entities>
<entity id="1" version="123456789">
<name>xxxxx</name>
<listId>0</listId>
<listCode>Oxxx</listCode>
<entityType>08</entityType>
<createdDate>03/03/1993</createdDate>
<lastUpdateDate>05/06/2011</lastUpdateDate>
<source>src</source>
<OriginalSource>o_src</OriginalSource>
<aliases>
<alias category="STRONG" type="Alias">USCJSC</alias>
<alias category="WEAK" type="Alias">'OSKOAO'</alias>
</aliases>
<programs>
<program type="21">prog</program>
</programs>
<sdfs>
<sdf name="OriginalID">9876</sdf>
</sdfs>
<addresses>
<address>
<address1>1141, SYA-KAYA STR.</address1>
<country>RU</country>
<postalCode>1234</postalCode>
</address>
<address>
<address1>90, MARATA UL.</address1>
<country>RU</country>
<postalCode>1919</postalCode>
</address>
</addresses>
<otherIds>
<childId>737606</childId>
<childId>737607</childId>
</otherIds>
</entity>
</entities>
</gwl>
I made a script to insert data from the XML to a SQL table. How can I insert child node into a table? I think I should replicate the row for each new child node but i don't know the best way to proceed.
Here is my SQL code
DECLARE #InputXML XML
SELECT #InputXML = CAST(x AS XML)
FROM OPENROWSET(BULK 'C:\MyFiles\sample.XML', SINGLE_BLOB) AS T(x)
SELECT
product.value('(#id)[1]', 'NVARCHAR(10)') id,
product.value('(#version)[1]', 'NVARCHAR(14)') ID
product.value('(name[1])', 'NVARCHAR(255)') name,
product.value('(listId[1])', 'NVARCHAR(9)')listId,
product.value('(listCode[1])', 'NVARCHAR(10)')listCode,
product.value('(entityType[1])', 'NVARCHAR(2)')entityType,
product.value('(createdDate[1])', 'NVARCHAR(10)')createdDate,
product.value('(lastUpdateDate[1])', 'NVARCHAR(10)')lastUpdateDate,
product.value('(source[1])', 'NVARCHAR(15)')source,
product.value('(OriginalSource[1])', 'NVARCHAR(50)')OriginalSource,
product.value('(aliases[1])', 'NVARCHAR(50)')aliases,
product.value('(programs[1])', 'NVARCHAR(50)')programs,
product.value('(sdfs[1])', 'NVARCHAR(500)')sdfs,
product.value('(addresses[1])', 'NVARCHAR(50)')addresses,
product.value('(otherIDs[1])', 'NVARCHAR(50)')otherIDs
FROM #InputXML.nodes('gwl/entities/entity') AS X(product)
You have a lot of different children here...
Just to show the principles:
DECLARE #xml XML=
N'<gwl>
<version>123456789</version>
<entities>
<entity id="1" version="123456789">
<name>xxxxx</name>
<listId>0</listId>
<listCode>Oxxx</listCode>
<entityType>08</entityType>
<createdDate>03/03/1993</createdDate>
<lastUpdateDate>05/06/2011</lastUpdateDate>
<source>src</source>
<OriginalSource>o_src</OriginalSource>
<aliases>
<alias category="STRONG" type="Alias">USCJSC</alias>
<alias category="WEAK" type="Alias">''OSKOAO''</alias>
</aliases>
<programs>
<program type="21">prog</program>
</programs>
<sdfs>
<sdf name="OriginalID">9876</sdf>
</sdfs>
<addresses>
<address>
<address1>1141, SYA-KAYA STR.</address1>
<country>RU</country>
<postalCode>1234</postalCode>
</address>
<address>
<address1>90, MARATA UL.</address1>
<country>RU</country>
<postalCode>1919</postalCode>
</address>
</addresses>
<otherIds>
<childId>737606</childId>
<childId>737607</childId>
</otherIds>
</entity>
</entities>
</gwl>';
-The query will fetch some values from several places.
--It should be easy to get the rest yourself...
SELECT #xml.value('(/gwl/version/text())[1]','bigint') AS [version]
,A.ent.value('(name/text())[1]','nvarchar(max)') AS [Entity_Name]
,A.ent.value('(listId/text())[1]','int') AS Entity_ListId
--more columns taken from A.ent
,B.als.value('#category','nvarchar(max)') AS Alias_Category
,B.als.value('text()[1]','nvarchar(max)') AS Alias_Content
--similar for programs and sdfs
,E.addr.value('(address1/text())[1]','nvarchar(max)') AS Address_Address1
,E.addr.value('(country/text())[1]','nvarchar(max)') AS Address_Country
--and so on
FROM #xml.nodes('/gwl/entities/entity') A(ent)
OUTER APPLY A.ent.nodes('aliases/alias') B(als)
OUTER APPLY A.ent.nodes('programs/program') C(prg)
OUTER APPLY A.ent.nodes('sdfs/sdf') D(sdfs)
OUTER APPLY A.ent.nodes('addresses/address') E(addr)
OUTER APPLY A.ent.nodes('otherIds/childId') F(ids);
The idea in short:
We read non-repeating values (e.g. version) from the xml variable directly
We use .nodes() to return repeating elements as derived sets.
We can use a cascade of .nodes() to dive deeper into repeating child elements by using a relativ Xpath (no / at the beginning).
You have two approaches:
Read the XML like above into a staging table (simply by adding INTO #tmpTable before FROM) and proceed from there (will need one SELECT ... GROUP BY for each type of child).
Create one SELECT per type of child, using only one of the APPLY lines and shift the data into specific child tables.
I would tend to the first one.
This allows to do some cleaning, generate IDs, check for business rules, before you shift this into the target tables.

nested element FOR XML in 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>

Read XML file into SQL Server database

I'm trying to read an XML file into a database table that already exists.
The problem is that the XML tags and the database columns don't have the same name although they have the same datatype. Therefore I'd like to "translate" the XML tags into the database columns so that the the input to the database becomes possible.
I'm not sure how to do that however.
Here is what I've done so far.
static void writeToDatabase()
{
XmlDocument doc= new XmlDocument();
try {
// Reading the xml
doc.Load("C:\\Temp\navetout.xml");
DataTable dt = new DataTable();
// Code here to read the xml into an already existing database table?
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
The database is located on another server, I've included this in the app.config
<connectionStrings>
<add name="CS"
connectionString="Data Source=tsrv2062;Initial Catalog=BUMS;Integrated Security=True"/>
</connectionStrings>
Let's say for an example that the XML file has the tags "Name" while the database table column has the column "Firstname".
XML example:
<?xml version="1.0" encoding="utf-8"?>
<ArrayOfFolkbokforingspostTYPE xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<FolkbokforingspostTYPE>
<Sekretessmarkering xsi:nil="true" />
<Personpost>
<PersonId>
<PersonNr>7527245452542</PersonNr>
</PersonId>
<HanvisningsPersonNr xsi:nil="true" />
<Namn>
<Tilltalsnamnsmarkering>20</Tilltalsnamnsmarkering>
<Fornamn>skjdgnsdng</Fornamn>
<Mellannamn xsi:nil="true" />
<Efternamn>sdsdgsdgs</Efternamn>
<Aviseringsnamn xsi:nil="true" />
</Namn>
<Folkbokforing>
<Folkbokforingsdatum>20060512</Folkbokforingsdatum>
<LanKod>56</LanKod>
<KommunKod>77</KommunKod>
<ForsamlingKod xsi:nil="true" />
<Fastighetsbeteckning>PÅLNGE 6:38</Fastighetsbeteckning>
<FiktivtNr>0</FiktivtNr>
</Folkbokforing>
<Adresser>
<Folkbokforingsadress>
<CareOf xsi:nil="true" />
<Utdelningsadress1 xsi:nil="true" />
<Utdelningsadress2>sgdsdgsdgs</Utdelningsadress2>
<PostNr>78965</PostNr>
<Postort>PÅLÄNG</Postort>
</Folkbokforingsadress>
<Riksnycklar>
<FastighetsId>46464545</FastighetsId>
<AdressplatsId>764846846</AdressplatsId>
<LagenhetsId>45465654645</LagenhetsId>
</Riksnycklar>
</Adresser>
<Fodelse>
<HemortSverige>
<FodelselanKod>00</FodelselanKod>
<Fodelseforsamling>NEDERKALIX</Fodelseforsamling>
</HemortSverige>
</Fodelse>
<Medborgarskap>
<MedborgarskapslandKod>SE</MedborgarskapslandKod>
<Medborgarskapsdatum>0</Medborgarskapsdatum>
</Medborgarskap>
</Personpost>
</FolkbokforingspostTYPE>
</ArrayOfFolkbokforingspostTYPE>
These are the columns of the database table:
PersonalIdentityNumber
ProtectedIdentity
ReferedCivicRegistrationNumber
UnregistrationReason
UnregistrationDate
MessageComputerComputer
GivenNameNumber
FirstName
MiddleName
LastName
NotifyName
NationalRegistrationDate
NationalRegistrationCountyCode
NationalRegistrationMunicipalityCode
NationalRegistrationCoAddress
NationalRegistrationDistributionAddress1
NationalRegistrationDistributionAddress2
NationalRegistrationPostCode
NationalRegistrationCity
NationalRegistrationNotifyDistributionAddress
NationalRegistrationNotifyPostCode
NationalRegistrationNotifyCity
ForeignDistrubtionAddress1
ForeignDistrubtionAddress2
ForeignDistrubtionAddress3
ForeignDistrubtionCountry
ForeignDate
BirthCountyCode
BirthParish
ForeignBirthCity
CitizenshipCode
CitizenshipDate
Email
Telephone
Mobiletelephone
Gender
NotNewsPaper
Note
StatusCode
NationalRegistrationCode
RegistrationDate
LastUpdatedFromNavet
TemporaryDistrubtionAddress1
TemporaryDistrubtionAddress2
TemporaryDistrubtionAddress3
TemporaryDistrubtionCountry
Password
VisibilityLevel
LastChangedBy
LastChangedDate
SeamanIdentity
Category
Here for an example, the <PersonNr> tagg and the databse column PersonalIdentityNumber are the same.
The column that doesn't match with the XML-tags are supposed to returning null.
Before reading the the XML data into the database table, I suppose the XML-tags has to be translated into the Database table column. In this case "Firstname".
Can anyone help me out with this "translation" and the reading into the database table.
DECLARE #xml XML
SELECT #xml = BulkColumn
FROM OPENROWSET(BULK 'D:\sample.xml', SINGLE_BLOB) x
SELECT
t.c.value('(PersonId/PersonNr/text())[1]', 'VARCHAR(100)'),
t.c.value('(Namn/Tilltalsnamnsmarkering/text())[1]', 'INT')
FROM #xml.nodes('*:ArrayOfFolkbokforingspostTYPE/*:FolkbokforingspostTYPE/*:Personpost') t(c)
This is how I used to do. This is not a solutionm but you may refer this.
EXEC sp_xml_preparedocument #XML_OUT OUTPUT, #XML_DATA;
Here, #XML_DATA is the XML data you pass. #XML_OUT is just an INT type.
SELECT * INTO #TEMP
FROM OPENXML(#XML_OUT,'DATA/INNER_TAG', 1)
WITH
(
a VARCHAR(500),
b VARCHAR(500),
c INT,
d VARCHAR(20)
)
But these name1, name2 etc need to be the same as in XML file.
So I use INSERT INTO SELECT Query to insert this data into specified table. Like,
INSERT INTO OriginalTable
(
name1,
name2,
name3,
name4
)
SELECT
a
b,
c,
d
FROM #TEMP

Extract XML header information into SQL server

My process involves getting a large XML file on a daily basis.
I have developed an SSIS package (2008 r2) which first gets rid of the multiple namespaces via a XSLT and then imports data into 40 tables (due to its complexity) by using the XML source object.
Here is the watered down version of a test xml file
<?xml version="1.0" encoding="UTF-8"?>
<s:Test xmlns:s="http://###.##.com/xml"
<sequence>62</sequence>
<generated>2015-04-28T00:59:38</generated>
<report_date>2015-04-27</report_date>
<orders>
<order>
</order>
</orders>
My question is: The XML source imports all the Orders with its nested attributes. How do I extract the 'report_date' and 'generated' from the header?
Any help would be much appreciated.
Thanks
SD
You can use XML method value() passing proper XPath/XQuery expression as parameter. For demo, consider the following table and data :
CREATE TABLE MyTable (id int, MyXmlColumn XML)
DECLARE #data XML = '<?xml version="1.0" encoding="UTF-8"?>
<s:Test xmlns:s="http://###.##.com/xml">
<sequence>62</sequence>
<generated>2015-04-28T00:59:38</generated>
<report_date>2015-04-27</report_date>
<orders>
<order>
</order>
</orders>
</s:Test>'
INSERT INTO Mytable VALUES(1,#data)
You can use the following query to get generated and report_date data :
SELECT
t.MyXmlColumn.value('(/*/generated)[1]','datetime') as generated
, t.MyXmlColumn.value('(/*/report_date)[1]','date') as report_date
FROM Mytable t
SQL Fiddle Demo
output :
generated report_date
----------------------- -----------
2015-04-28 00:59:38.000 2015-04-27

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)

Resources