How do you read an XML file in SQL? - sql

I am using SQL Server 2014 to query XML text using xquery. I am able to insert portions of XML text to query but I need to be able to point to a local file to read and query it and cannot figure out how to do that. Below is what I have for what I am currently doing.
declare #xmldata xml
set #xmldata = '
<Orders>
<Order OrderID="100" OrderDate="1/30/2012">
<OrderDetail ProductID="1" Quantity="3">
<Price>350</Price>
</OrderDetail>
<OrderDetail ProductID="2" Quantity="8">
<Price>500</Price>
</OrderDetail>
<OrderDetail ProductID="3" Quantity="10">
<Price>700</Price>
</OrderDetail>
</Order>
<Order OrderID="200" OrderDate="2/15/2012">
<OrderDetail ProductID="4" Quantity="5">
<Price>120</Price>
</OrderDetail>
</Order>
</Orders>'
SELECT x.c.value('(OrderDetail)[2]', 'varchar(100)') as OrderDetail
FROM #xmldata.nodes('/Orders/Order') x(c)
--XMl File Location: "C:\Users\User\X\Example.xml")
Thanks in advance!

Try this https://msdn.microsoft.com/en-CA/library/ms191184.aspx
INSERT INTO T(XmlCol)
SELECT * FROM OPENROWSET(
BULK 'c:\SampleFolder\SampleData3.txt',
SINGLE_BLOB) AS x;

Related

How read xml data from a xml file without tags in SQL Server?

I know how to read the xml data from a file where the info is organized in tags, I mean a file like this:
<?xml version='1.0' encoding='UTF-8'?>
<dataset>
<Administrador>
<id> 8 </id>
<nombre> Nelle </nombre>
<valorDocId> 8399335355 </valorDocId>
<contrasenna> Glenn </contrasenna>
</Administrador>
<Administrador>
<id> 9 </id>
<nombre> Gayler </nombre>
<valorDocId> 1310348693 </valorDocId>
<contrasenna> Madonna </contrasenna>
</Administrador>
</dataset>
The code I used to read it is:
use Proyecto1
declare #filedata XML
select #filedata=BulkColumn from OpenRowSet(Bulk'File directory', Single_blob) x;
insert into Table(id, nombre, valorDocId, clave)
select
xData.value('id[1]', 'int') id,
xData.value('nombre[1]','varchar(30)') nombre,
xData.value('valorDocId[1]','int') valorDocId,
xData.value('contrasenna[1]','varchar(20)') clave
from #fileData.nodes('/dataset/Administrador') as
x(xData)
But now I need to read a xml file that is not organized in tags, at least not like the last one, the xml is like this:
<?xml version='1.0' encoding='UTF-8'?>
<dataset>
<Administrador id="1" nombre="Nelle" valorDocId="8399335355" contrasenna="Glenn"/>
<Administrador id="2" nombre="Gayler" valorDocId="1310348693" contrasenna="Madonna"/>
</dataset>
But the code I used before doesn't works, it throws an error that says that I can't insert a NULL value in the column 'id', so what I supposed is that the data is not being read. So how can I read that second file?
Example
Declare #XML xml = '
<dataset>
<Administrador id="1" nombre="Nelle" valorDocId="8399335355" contrasenna="Glenn"/>
<Administrador id="2" nombre="Gayler" valorDocId="1310348693" contrasenna="Madonna"/>
</dataset>
'
Select id = x.v.value('#id','int')
,nombre = x.v.value('#nombre','varchar(50)')
,valorDocId = x.v.value('#valorDocId','varchar(50)')
,contrasenna = x.v.value('#contrasenna','varchar(50)')
From #Xml.nodes('dataset/Administrador') x(v)
Returns
id nombre valorDocId contrasenna
1 Nelle 8399335355 Glenn
2 Gayler 1310348693 Madonna
EDIT - To Get your XML from a File
Declare #XML xml
Select #XML = BulkColumn FROM OPENROWSET(BULK 'C:\Working\SomeXMLFile.xml', SINGLE_BLOB) x;
Select id = x.v.value('#id','int')
,nombre = x.v.value('#nombre','varchar(50)')
,valorDocId = x.v.value('#valorDocId','varchar(50)')
,contrasenna = x.v.value('#contrasenna','varchar(50)')
From #Xml.nodes('dataset/Administrador') x(v)

XML to SQL - SQL Server

I'm traversing an XML file to read nodes and fill into to SQL Server tables. I have a Root node having Department node which further may have one or more as element. I want to select all the possible values from in a SQL result set.
Please find below XML I'm referring:
DECLARE #x XML='
<Root>
<Department>
<DeptID>D101</DeptID>
<DeptID>D102</DeptID>
</Department>
</Root>'
I'm using below SQL Query to get the data from XML but I can read only first DeptID as I'm passing [1] inside DeptID[1]. If I pass [2] I can get thee second value. But in real life scenario, I won't be able to know how many DeptID would be there in the XML. So I want a generic script to read as many as DeptIDs comes in XML.
SELECT n.value('DeptID[1]','varchar(10)') AS DeptID FROM #x.nodes('/Root/Department') R(n)
You can use OpenXMl method of sql server to get more elements in table as follows.
Step 1: Suppose this is your sample XML data.
DECLARE #XML XML='
<ROOT>
<Customers>
<Customer CustomerID="C001" CustomerName="Arshad Ali">
<Orders>
<Order OrderID="10248" OrderDate="2012-07-04T00:00:00">
<OrderDetail ProductID="10" Quantity="5" />
<OrderDetail ProductID="11" Quantity="12" />
<OrderDetail ProductID="42" Quantity="10" />
</Order>
</Orders>
<Address> Address line 1, 2, 3</Address>
</Customer>
<Customer CustomerID="C002" CustomerName="Paul Henriot">
<Orders>
<Order OrderID="10245" OrderDate="2011-07-04T00:00:00">
<OrderDetail ProductID="11" Quantity="12" />
<OrderDetail ProductID="42" Quantity="10" />
</Order>
</Orders>
<Address> Address line 5, 6, 7</Address>
</Customer>
<Customer CustomerID="C003" CustomerName="Carlos Gonzlez">
<Orders>
<Order OrderID="10283" OrderDate="2012-08-16T00:00:00">
<OrderDetail ProductID="72" Quantity="3" />
</Order>
</Orders>
<Address> Address line 1, 4, 5</Address>
</Customer>
</Customers>
</ROOT>'
Step 2: Use of OPENXML method to get elements at any level as follows.
DECLARE #hDoc AS INT, #SQL NVARCHAR (MAX)
EXEC sp_xml_preparedocument #hDoc OUTPUT, #XML
SELECT CustomerID, CustomerName, Address, OrderID, OrderDate, ProductID, Quantity
FROM OPENXML(#hDoc, 'ROOT/Customers/Customer/Orders/Order/OrderDetail')
WITH
(
CustomerID [varchar](50) '../../../#CustomerID',
CustomerName [varchar](100) '../../../#CustomerName',
Address [varchar](100) '../../../Address',
OrderID [varchar](1000) '../#OrderID',
OrderDate datetime '../#OrderDate',
ProductID [varchar](50) '#ProductID',
Quantity int '#Quantity'
)
EXEC sp_xml_removedocument #hDoc
GO
Above steps will give you following Output.
Try it like this
DECLARE #x XML='
<Root>
<Department>
<DeptID>D101</DeptID>
<DeptID>D102</DeptID>
</Department>
</Root>';
SELECT d.value('text()[1]','varchar(10)') AS DeptID
FROM #x.nodes('/Root/Department/DeptID') A(d);
Your own code
SELECT n.value('DeptID[1]','varchar(10)') AS DeptID
FROM #x.nodes('/Root/Department') R(n)
... follows the right idea. But .nodes() must return the repeating element, which is <DeptID>. Your approach is looking for the first <DeptID> within <Department> actually

Parse the XML in SQL Server

<ROOT>
<arn>arn001</arn>
<arn>arn002</arn>
</ROOT>
Tried the following code though
SELECT
ARN.value('(//arn/text())[1]','VARCHAR(100)') AS arns --TAG
FROM
#xml.nodes('/ROOT')AS TEMPTABLE(ARN)
It returns only first value
Try this way :
declare #xml xml = '<ROOT>
<arn>arn001</arn>
<arn>arn002</arn>
</ROOT>'
SELECT
X.value('.','VARCHAR(100)') AS arns
FROM
#xml.nodes('/ROOT/arn')AS T(X)
SQL Fiddle

SQL XML Replacing elements

Please help! Is it possible to replace elements within an xml field of an sql database with other elements. I have tried using .modify(replace value of) but I can only replace text within elements rather than nodes.
Ultimately I am trying to update an element which may or may not contain other elements, with another element (possibly of the same name) within an XML field. (I am using SQL Server 2008)
E.g:
<Root>
<Sub>
<Value1>
</Value1>
<Value2>
</Value2>
<Value3>
</Value3>
</Sub>
</Root>
Would be replaced by:
<Root>
<SubVERSION2>
<Value1>
</Value1>
<Value2>
</Value2>
<Value3>
</Value3>
</SubVERSION2>
</Root>
Any help would be very much appreciated!
You can recreate your XML:
declare #x xml = '<Root>
<Sub>
<Value1>1
</Value1>
<Value2>2
</Value2>
<Value3>3
</Value3>
</Sub>
</Root>'
select cast(('<Root>' +
cast(
(
select t.c.query('.')
from #x.nodes('Root/Sub/*') t(c)
for xml path(''), root('SubVERSION2')
) as nvarchar(max)) + '</Root>') as xml)
produces desired output:
<Root>
<SubVERSION2>
<Value1>1
</Value1>
<Value2>2
</Value2>
<Value3>3
</Value3>
</SubVERSION2>
</Root>
declare #T table(XMLCol xml)
insert into #T values ('
<Root>
<Sub>
<Value1></Value1>
<Value2></Value2>
<Value3></Value3>
</Sub>
</Root>')
update #T set
XMLCol = XMLCol.query('for $s in Root/Sub
return
<Root>
<SubVERSION2>
{ $s/* }
</SubVERSION2>
</Root>')
Result:
<Root>
<SubVERSION2>
<Value1 />
<Value2 />
<Value3 />
</SubVERSION2>
</Root>

Getting the value of dc:creator using SQL XML

I am unsure how to get the value of dc:creator from an RSS-feed using SQL.
This is my xml/rss-feed:
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" version="2.0">
<channel>
<title>Foobar RSS</title>
<link>http://www.foobar.com/</link>
<description>RSS feed</description>
<language>en</language>
<ttl>15</ttl>
<item>
<title>This is my title</title>
<link>http://www.foobar.com/link/blabla</link>
<description>Bla..bla..bla..</description>
<dc:creator>John Doe</dc:creator>
<guid isPermaLink="false">00082EA751F1D905DE00E7CFA2417DA9</guid>
<pubDate>Wed, 26 Oct 2011 00:00:00 +0200</pubDate>
</item>
</channel>
</rss>
In my SQL I use something like this to get the values - e.g for pubDate I use something like this:
DECLARE #xml XML
SET #xml = cast('my rss feed here' AS xml)
SELECT
convert(datetime,substring(T.nref.value('pubDate[1]','nvarchar(100)'),6,20)) as pubdate,
FROM #xml.nodes('//item') AS T(nref)
This works fine, but when I am trying to get dc:creator value 'John Doe', the following just gives me an error:
SELECT
T.nref.value('dc:creator','nvarchar(100)') as creator
FROM #xml.nodes('//item') AS T(nref)
error:
XQuery [value()]: The name "dc" does not denote a namespace.
I need to be able to select multiple columns from the rss-feed. Can anybody provide a solution or direction to get the value of dc:creator?
I have another question - how would you construct the code if you are doing it in a sub select?
E.g.
INSERT INTO RSSResults (ID, pubDate)
SELECT #ID, tbl.pubDate FROM (
;WITH XMLNAMESPACES('http://purl.org/dc/elements/1.1/' AS dc)
SELECT
RSS.Item.value('(dc:creator)[1]', 'nvarchar(100)') as pubDate
FROM
#xml.nodes('/rss/channel/item') as RSS(Item)) AS tbl
The code breaks at ";WITH XMLNAMESPACES". Is it possible to include the namespace directly in the statement somehow?
Try something like this:
DECLARE #xml XML
SET #xml = cast('my rss feed here' AS xml)
;WITH XMLNAMESPACES('http://purl.org/dc/elements/1.1/' AS dc)
SELECT
#xml.value('(rss/channel/item/dc:creator)[1]', 'nvarchar(100)')
If you need to catch multiple items - try this:
DECLARE #xml XML
SET #xml = cast('my rss feed here' AS xml)
;WITH XMLNAMESPACES('http://purl.org/dc/elements/1.1/' AS dc)
SELECT
RSS.Item.value('(dc:creator)[1]', 'nvarchar(100)')
FROM
#xml.nodes('/rss/channel/item') as RSS(Item)