Showing XML Data in SQL table - sql

I have an xml file which shows data like this:
<learner>
<name>Smith</name>
<ULN>123456</ULN>
</learner>
<learner>
<name>Jones</name>
<ULN>56789</ULN>
</learner>
I have a table that stores the files as varchar (max) as I cannot upload directly as xml from my front end system.
I am able to read the file as an xml file by creating a table:
declare #ILRDATA table (Data xml)
Insert into #ILRDATA (Data)
select FileUpload from ILRDATA.dbo.ILRUpload
select * from #ILRDATA
I now want to create a #table with the columns (Name varchar (50), ULN varchar (10))
I want to then populate this with the xml data
Can someone please help me before I waste a whole day trying to figure this out.
Thanks

select
t.c.value('name[1]', 'nvarchar(50)') as name,
t.c.value('ULN[1]', 'nvarchar(10)') as ULN
from #ILRDATA as d
outer apply d.Data.nodes('learner') as t(c)

Related

How to display XML column data

I have a table column consist with the XML files. I want to read XML data and display it.
I come up with the following code. But it read only one row in the column
want to display other XML data also
declare #xml xml
select #xml = event_data_XML from #temp
SELECT * FROM (
SELECT
CAST(f.x.query('data(#name)') as varchar(150)) as data_name,
CAST(f.x.query('data(value)') as varchar(150)) as data_value
FROM #xml.nodes('/event') as t(n)
CROSS APPLY t.n.nodes('data') as f(x)) X
PIVOT (MAX(data_value) FOR data_name IN (NTDomainName, DatabaseName, ServerName)) as pvt
Output should be like this(NTDomainName, DatabaseName, ServerName are xml data)
There are a bunch of ways you could do this. I'll show you a way I think you'd find easiest.
To start, here's a table with a little test data:
CREATE TABLE dbo.stuff (
id int identity (1,1) primary key
, event_data_xml xml
, create_date datetime default(getdate())
, is_active bit default(1)
);
INSERT INTO dbo.stuff (event_data_xml)
VALUES ('<event name="thing" package="as">something</event>')
INSERT INTO dbo.stuff (event_data_xml)
VALUES ('<event name="otherthing" package="as">something else</event>')
---All records
SELECT * FROM dbo.[stuff];
Make sense so far? Here's the query I'd use if I wanted to mix XML data and column data:
---Parsed up
SELECT event_data_xml.value('/event[1]', 'nvarchar(max)') AS [parsed element #text]
, event_data_xml.value('/event[1]/#name', 'nvarchar(max)') AS [parsed attribute value]
, create_date --column from table
FROM dbo.stuff
WHERE is_active = 1;
Using the value() function on the XML column passing in an xpath to what I want to display and SQL Server data type for how I want it returned.
Just make sure you're selecting a single value with your xpath expression.

Regarding Dynamic sql construction

when we load xml into cursor then we specify column name and their datatype and size. instead of specifying manually how could i make that area dynamic. suppose my tsql as follows
Exec sp_xml_preparedocument #XMLFormat OUTPUT, #DetailXml
-- Create Cursor from XML Table
Declare CurDetailRecord
Cursor For
Select productid,unit,rate,qty,amount
From Openxml (#XMLFormat, '/NewDataSet/PurchaseOrderDetail', 2)
With
(
productid Varchar(10),
unit Varchar(50),
rate decimal(18,2),
qty decimal(18,3),
amount decimal(18,2)
)
here as a example
productid Varchar(10),
unit Varchar(50)
etc i am specifying and also specify their data tyoe & size.
so how could i construct this area dynamically and fetch the column name and data type & size dynamically.
please guide me thanks.
You can get column names(which are nodes inside PurchasePrderDetail node) like this:
declare #xml xml='<NewDataSet><PurchaseOrderDetail>
<productid>19125</productid>
</PurchaseOrderDetail></NewDataSet>'
SELECT b.value('local-name(.)','nvarchar(128)')ColumnName,
LEN(b.value('.','nvarchar(128)'))MaxLength
FROM #xml.nodes('/NewDataSet/PurchaseOrderDetail/*') a(b)
So you can generate dynamic SQL statement to create cursor with appropriate column names and length like varchar(MaxLength).
But you can not get datatypes from XML without knowing real column names because data in xml is just text and f.e. "5" can be int type and also just a text.
EDIT
If you know table name, you can built dynamic SQL statement using metadata from that table using this:
; With cols as(
SELECT COLUMN_NAME,
UPPER(DATA_type)
+
case when data_type like '%char' then
case when CHARACTER_MAXIMUM_LENGTH=-1 THEN ' (MAX)'
else ' ('+CAST(CHARACTER_MAXIMUM_LENGTH as nvarchar)+')'
END
ELSE ''
END ColConv
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME='PurchaseOrderDetail'),
XMLS as(
SELECT b.value('local-name(.)','nvarchar(128)')ColumnName,
b.value('.','nvarchar(128)')Value
FROM #xml.nodes('/NewDataSet/PurchaseOrderDetail/*') a(b)
)
SELECT XMLS.ColumnName,'CAST ('''+XMLS.Value+''' AS '+ ColConv+''')' FROM XMLS
JOIN cols ON XMLS.ColumnName=cols.COLUMN_NAME
As output you will have column name and value with appropriate CAST clause. Then you can build dynamic statement what you need.
Usually the information of data types and field names are describes in the XSD file (XML Schema Definition).
So you need to have a valid XSD file for each of your XML file then you can retrieve the fields name and data type.
Here a link to understand better the XSD
And here how to deal with XSD and XML step by step
Hope it helps you

selecting from sql

<suggestions>
<suggestion>
<description>plate.</description>
</suggestion>
<suggestion>
<description>snack.</description>
</suggestion>
</suggestions>
DECLARE #Suggestions TABLE (
[Description] VARCHAR(800)
)
I have above xml in a XML type varible in my stored procedure
how can i insert each text between description tags
in to the table #Suggestions
Try this:
DECLARE #input XML = '<suggestions>
<suggestion>
<description>plate.</description>
</suggestion>
<suggestion>
<description>snack.</description>
</suggestion>
</suggestions>'
DECLARE #Suggestions TABLE ([Description] VARCHAR(800))
INSERT INTO #Suggestions
SELECT
Sugg.value('(description)[1]', 'varchar(800)')
FROM
#input.nodes('/suggestions/suggestion') AS Tbl(Sugg)
SELECT * FROM #Suggestions
The #input.nodes() expression basically turns each <suggestion> node into a row in the "pseudo" table called Tbl(Sugg). From those "rows" (each basically another XML fragment), you then select out the value you're interested in - here the contents of the <description> XML element inside that XML fragment.
You can use LINQ-to-XML to get all suggestions, then you can insert that data into the table.

how to get values inside an xml column, when it's of type nvarchar

My question is similar to this one: Choose a XML node in SQL Server based on max value of a child element
except that my column is NOT of type XML, it's of type nvarchar(max).
I want to extract the XML node values from a column that looks like this:
<Data>
<el1>1234</el1>
<el2>Something</el2>
</Data>
How can I extract the values '1234' and 'Something' ?
doing a convert and using the col.nodes is not working.
CONVERT(XML, table1.col1).value('(/Data/el1)[1]','int') as 'xcol1',
After that, I would like to do a compare value of el1 (1234) with another column, and update update el1 as is. Right now I'm trying to just rebuild the XML when passing the update:
ie
Update table set col1 ='<Data><el1>'+#col2+'</el1><el2>???</el2>
You've got to tell SQL Server the number of the node you're after, like:
(/Data/el1)[1]
^^^
Full example:
declare #t table (id int, col1 varchar(max))
insert #t values (1, '<Data><el1>1234</el1><el2>Something</el2></Data>')
select CAST(col1 as xml).value('(/Data/el1)[1]', 'int')
from #t
-->
1234
SQL Server provides a modify function to change XML columns. But I think you can only use it on columns with the xml type. Here's an example:
declare #q table (id int, col1 xml)
insert #q values (1, '<Data><el1>1234</el1><el2>Something</el2></Data>')
update #q
set col1.modify('replace value of (/Data/el1/text())[1] with "5678"')
select *
from #q
-->
<Data><el1>5678</el1><el2>Something</el2></Data>
At the end of the day, SQL Server's XML support makes simple things very hard. If you value maintainability, you're better off processing XML on the client side.

How to get Sql Server XML variable into TEXT column

I need to update an XML document stored in a Microsoft SQL Server database, however the vendor of the product chose to store the XML in a TEXT column.
I've been able to extract the TEXT into an XML-type variable and perform the update I need on the xml within this variable, but when I try to UPDATE the column to push the change back to the database, I run into trouble.
Looking through the documentation it appears that it's not possible to simply CAST/CONVERT an XML type variable to insert it into a TEXT column, but I would think there is some way to extract the xml "string" from the XML-type variable and UPDATE the column using this value.
Any suggestions are appreciated, but I would like to keep the solution pure SQL that it can be run directly (no C# custom function, etc.); just to keep the impact on the database minimal.
(note: isn't it a bit absurd that you can't just CAST XML as TEXT? I'm just saying...)
Casting the XML as VARCHAR(MAX) works.
declare #xml xml
declare #tblTest table (
Id int,
XMLColumn text
)
insert into #tblTest
(Id, XMLColumn)
values
(1, '<MyTest><TestNode>A</TestNode></MyTest>')
set #xml = '<MyTest><TestNode>A</TestNode><TestNode>B</TestNode></MyTest>'
update #tblTest
set XMLColumn = cast(#xml as varchar(max))
where Id = 1
select Id, XMLColumn from #tblTest