How to Insert Different XML Field values as rows in a table - sql

I Have an xml as mentioned below,
declare #Message as xml
set #Message='<message>
<body>
<ID>1</ID>
<setup_time>10</setup_time>
<prod_cycle_time>10</prod_cycle_time>
<unit>cas</unit>
<Flag>NULL</Flag>
<FillingPO>NULL</FillingPO>
<PackAtCAN1>NULL</PackAtCAN1>
</body>
</message>'
from above xml structure need to insert few fields data as mentioned below format
ID Desc Value
1 setup_time 10
1 prod_cycle_time 10
1 unit Case
1 Flag NULL

You can also use XQuery to first transform your XML:
declare #transform xml
set #transform = #message.query('
let $capture := ("setup_time","prod_cycle_time","unit","Flag")
for $item in /message/body/*
let $id := $item/../ID
where $capture = local-name($item)
return <Row>
<ID>{$id/text()}</ID>
<Desc>{local-name($item)}</Desc>
<Value>{$item/text()}</Value>
</Row>
')
SELECT x.value('ID[1]','int') AS ID,
x.value('Desc[1]','varchar(max)') AS [Desc],
x.value('Value[1]','varchar(max)') AS Value
FROM #transform.nodes('/Row') tmp(x)

Looks like you want to get the values out from the XML and then do an unpivot.
Use value() function to extract values from the XML and you can use union all to do the unpivot.
declare #Message as xml
set #Message='
<message>
<body>
<ID>1</ID>
<setup_time>10</setup_time>
<prod_cycle_time>10</prod_cycle_time>
<unit>cas</unit>
<Flag>NULL</Flag>
<FillingPO>NULL</FillingPO>
<PackAtCAN1>NULL</PackAtCAN1>
</body>
</message>'
declare #ID int
set #ID = #Message.value('(/message/body/ID/text())[1]', 'int')
select #ID as ID,
'setup_time' as [Desc],
#Message.value('(/message/body/setup_time/text())[1]', 'nvarchar(50)') as Value
union all
select #ID,
'prod_cycle_time',
#Message.value('(/message/body/prod_cycle_time/text())[1]', 'nvarchar(50)')
union all
select #ID,
'unit',
#Message.value('(/message/body/unit/text())[1]', 'nvarchar(50)')
union all
select #ID,
'Flag',
#Message.value('(/message/body/Flag/text())[1]', 'nvarchar(50)')

Related

Concatenate XML variables in SQL Server

I have a query in a stored procedure retrieving some data in XML format to be returned in a variable #xml_data, like this:
SELECT #xml_data = (
SELECT * FROM (
SELECT 1 AS Tag
,0 AS Parent
.....
FROM MyTable
WHERE id = #id
UNION ALL
SELECT 2 AS Tag
,1 AS Parent
....
FROM MyTable2
WHERE id = #id
UNION ALL
SELECT 3 AS Tag
,2 AS Parent
....
FROM MyTable3
WHERE id = #id
) results
FOR XML EXPLICIT, TYPE)
This is working like the proverbial dream :)
However, I'd like to concatenate a header to this XML (e.g. <xml version="1.0" encoding="ISO-8859-1"/>) and can't figure out how to do it. I've tried converting to NVARCHAR, selecting the two variables in one statement but can't seem to get it right.
Can anyone help??
Thanks :)
Try doing like this:
DECLARE #x xml
DECLARE #strXML varchar(MAX)
SET #x=N'<Employee><Name>Luftwaffe</Name></Employee>'
set #strXML = '<xml version="1.0" encoding="ISO-8859-1"/>' + CONVERT(varchar(MAX),#x)
SELECT #strXML
Hope it helps !
You can just declare the string at the beginning and concatenate them together:
declare #xml_data nvarchar(MAX)
set #xml_data = '<xml version="1.0" encoding="ISO-8859-1"/>'
SELECT #xml_data = #xml_data + (
SELECT * FROM (
SELECT 1 AS Tag
,0 AS Parent
.....
FROM MyTable
WHERE id = #id
UNION ALL
SELECT 2 AS Tag
,1 AS Parent
....
FROM MyTable2
WHERE id = #id
UNION ALL
SELECT 3 AS Tag
,2 AS Parent
....
FROM MyTable3
WHERE id = #id
) results
FOR XML EXPLICIT, TYPE)
This is the easiest way, in my opinion:
declare #xml1 xml
declare #xml2 xml
declare #xml3 xml
select #xml1='<name>testname</name>'
select #xml2='<value>testvalue</value>'
select #xml3 =
(
select #xml1 AS xml1, #xml2 AS xml2
for xml path('')
)
select #xml3

how to generate xml with element and attribute using xml explicit

im trying to generate xml in the following format:
<Root>
<Domain>Abc</Domain>
<Name>Xyz</Name>
<Contents>
<Content>
<ID>1</ID>
<Value>Test 1</Value>
<Record ID="1">Test 1</Record>
</Content>
<Content>
<ID>2</ID>
<Value>Test 2</Value>
<Record ID="2">Test 2</Record>
</Content>
</Contents>
</Root>
My query is as follows:
declare #TestTable table (ID int, Value varchar(100))
insert into #TestTable values (1,'Test 1')
insert into #TestTable values (2,'Test 2')
declare #Domain varchar(max)='Abc'
declare #Name varchar(max)='Xyz'
SELECT
1 AS Tag,
NULL AS Parent,
#Domain as 'Root!1!Domain!Element',
#Name as 'Root!1!Name!Element',
NULL as 'Contents!2!Element',
NULL as 'Content!3!ID!Element',
NULL as 'Content!3!Value!Element',
NULL as 'Content!3!Record!Element'
union
SELECT
2 AS Tag,
1 AS Parent,
NULL,NULL,NULL,NULL,NULL,NULL
union
select
3 as Tag,
2 as Parent,
NUll,NUll,NULL,
ID,Value,Value
from #TestTable
FOR XML EXPLICIT
my query does not produce the record tag completely, currently it is
<Record>Test 2</Record>
which should be as
<Record ID=2>Test 2</Record>
I tried all the possibilities but not getting the tag. Can anyone help me solving this issue.
I could not get the expected output from xml explicit, instead i used xml path and got the output. this is my updated query
SELECT
#Domain "Domain",
#Name "Name",
(
SELECT
ID "ID",
Value "Value",
(select
ID "#ID",
Value as "text()"
FOR XML PATH('Record'), ELEMENTS, TYPE )
FROM #TestTable
FOR XML PATH ('Content'), TYPE, ROOT('Contents')
)
FOR XML PATH ('Root')
you are welcome to post the fix which uses xml explicit.
Don't forget the ORDER BY when use FOR XML EXPLICIT.
SELECT
1 AS Tag,
NULL AS Parent,
#Domain as 'Root!1!Domain!Element',
#Name as 'Root!1!Name!Element',
NULL as 'Contents!2!Element',
NULL as 'Content!3!ID!Element',
NULL as 'Content!3!Value!Element',
NULL as 'Record!4!ID',
NULL as 'Record!4!'
union
SELECT
2 AS Tag,
1 AS Parent,
#Domain,NULL,NULL,NULL,NULL,NULL, null
union
select
3 as Tag,
2 as Parent,
#Domain,NUll,NULL,
ID,Value,null,null
from #TestTable
union
select
4 as Tag,
3 as Parent,
#Domain,NUll,NULL,
ID,Value,ID,Value
from #TestTable
ORDER BY 'Root!1!Domain!Element','Contents!2!Element','Content!3!ID!Element','Record!4!ID'
FOR XML EXPLICIT

SQL: How can I get the value of an attribute in XML datatype?

I have the following xml in my database:
<email>
<account language="en" ... />
</email>
I am using something like this now: but still have to find the attribute value.
SELECT convert(xml,m.Body).query('/Email/Account')
FROM Mail
How can I get the value of the language attribute in my select statement with SQL?
Use XQuery:
declare #xml xml =
'<email>
<account language="en" />
</email>'
select #xml.value('(/email/account/#language)[1]', 'nvarchar(max)')
declare #t table (m xml)
insert #t values
('<email><account language="en" /></email>'),
('<email><account language="fr" /></email>')
select m.value('(/email/account/#language)[1]', 'nvarchar(max)')
from #t
Output:
en
fr
This should work:
DECLARE #xml XML
SET #xml = N'<email><account language="en" /></email>'
SELECT T.C.value('#language', 'nvarchar(100)')
FROM #xml.nodes('email/account') T(C)
It depends a lot on how you're querying the document. You can do this, though:
CREATE TABLE #example (
document NText
);
INSERT INTO #example (document)
SELECT N'<email><account language="en" /></email>';
WITH XmlExample AS (
SELECT CONVERT(XML, document) doc
FROM #example
)
SELECT
C.value('#language', 'VarChar(2)') lang
FROM XmlExample CROSS APPLY
XmlExample.doc.nodes('//account') X(C);
DROP TABLE #example;
EDIT after changes to your question.
if the xml data is stored in sql server as a string column then use cast
select cast(your_field as XML)
.value('(/email/account/#language)[1]', 'varchar(20)')
from your_table

How to Generate xml from sql for below pattern

I'm writing one stored procedure, which I have to create a xml column from db.
µ = CHAR(181) this is value separator,
¶ = CHAR(182) this is row separator
This is the statement I wrote. I know its not well formed.
SELECT #xmlString= CAST('<root><Section> ID =' + REPLACE(REPLACE ('20211µ1¶20212µ2', CHAR(182),
'</Section><Section> ID ='),CHAR(181), ' Slno=') + '</Section></root>' AS XML)
This is the pattern which I need to display like this.
<root>
<sections id="20211" slno="1" ></sections>
<sections id="20215" slno="2" ></sections>
</root>
declare #s varchar(50) = '20211µ1¶20212µ2'
declare #xmlString xml
;with C as
(
select T.N.value('value[1]', 'int') as id,
T.N.value('value[2]', 'int') as slno
from (select cast('<item><value>'+replace(replace(#s, 'µ','</value><value>'), '¶','</value></item><item><value>')+'</value></item>' as xml)) as X(XMLCol)
cross apply X.XMLCol.nodes('item') as T(N)
)
select #xmlString =
(
select C.id as [#id] ,
C.slno as [#slno]
from C
for xml path('sections'), root('root'), type
)
select #xmlString
Result:
<root>
<sections id="20211" slno="1" />
<sections id="20212" slno="2" />
</root>

MS SQL 2005 Table to XML

I have a simple table in SQL Server 2005, I wish to convert this to XML (using the "FOR XML" clause). I'm having trouble getting my XML to look like the required output.
I've tried looking through various tutorials on the web, but I am struggling. Can someone help?
The table I have looks like this
TYPE,GROUP,VALUE
Books,Hardback,56
Books,Softcover,34
CDs,Singles,45
CDS,Multis,78
The output style I need is:
<data>
<variable name="TYPE">
<row>
<column>GROUP</column>
<column>VALUE</column>
</row>
<row>
<column>GROUP</column>
<column>VALUE</column>
</row>
</variable>
<variable name="TYPE">
<row>
<column>GROUP</column>
<column>VALUE</column>
</row>
<row>
<column>GROUP</column>
<column>VALUE</column>
</row>
</variable>
</data>
Edit:
As far as I can tell I require the multiple values. I'm generating XML for use with Xcelsius (Linking XML and Xcelsius) so have no control over in the formatting of the XML. I can generate the XML using ASP as per the linked tutorial, but I was hoping to get it straight from SQL Server.
Edit 2:
I was hoping for something elegant and tidy... but Godeke's example got the closest. Some fiddling with the SQL and I've come up with:
select
"type" as '#name',
"group" as 'row/column',
null as 'row/tmp',
"value" as 'row/column'
from tableName
for xml path('variable'), root('data')
Outputs almost in the exact way I wanted. The null/tmp line doesn't even output; it is just preventing the concatenation. Still the tag <variable name="TYPE"> repeats for each row, which I can't have.
As close as I can get is this:
select "type" as '#name', "group" as 'row/column1', "value" as 'row/column2'
from tableName
for xml path('variable'), root('data')
Naming two items the same ("column" and "column") isn't something I know how to do in one pass, but on the other hand it is an odd XML schema choice; normally elements have unique names if they contain distinct data. The obvious choice (name them both 'row/column') simply concatenates them in the output into one value.
Also note that each returned row will be a "variable" element distinct from the others. To get the nesting without redundant records will require a subquery:
select distinct "type" as '#name'
from Agent
for xml path('variable'), root('data')
was my first thought, but the distinct prevents nesting.
All this makes me think that to get the exact output you need you might have to use EXPLICIT mode. Perhaps my problem is for something like this I punt and use a DOMDocument in code :).
I prefer using for XML PATH, it provides a nicer way to control your elements etc.
See
But this is quite tricky
/*
create table #tablename
(
[type] varchar(20),
[group] varchar(20),
[value] varchar(20)
)
insert into #tablename select 'type1','group11','value111'
insert into #tablename select 'type1','group11','value112'
insert into #tablename select 'type1','group12','value121'
insert into #tablename select 'type1','group12','value122'
insert into #tablename select 'type2','group21','value211'
insert into #tablename select 'type2','group21','value212'
insert into #tablename select 'type2','group22','value221'
insert into #tablename select 'type2','group22','value222'
alter table #tablename add id uniqueidentifier
update #tablename set id = newid()
*/
select [type] as '#name',
(select
(select [column] from
(
select [group] as 'column', tbn1.type, tbn2.[group]
from #tablename tbn3 WHERE tbn3.type = tbn1.type and tbn2.[group] = tbn3.[group]
union
select [value], tbn1.type, tbn2.[group]
from #tablename tbn3 WHERE tbn3.type = tbn1.type and tbn2.[group] = tbn3.[group]
) as s
for xml path(''),type
)
from #tablename tbn2
where tbn2.type = tbn1.type
for xml path('row3'), type
)
from #tableName tbn1
GROUP BY [type]
for xml path('variable'), root('data')
gives you what you are asking for I, but elegant and tidy it is not.
The script below produces the desired format
<DATA>
<VARIABLE TYPE="Books">
<row TYPE="Books">
<GROUP>Hardback</GROUP>
<VALUE>56</VALUE>
</row>
<row TYPE="Books">
<GROUP>Softcover</GROUP>
<VALUE>34</VALUE>
</row>
</VARIABLE>
<VARIABLE TYPE="CDs">
<row TYPE="CDs">
<GROUP>Singles</GROUP>
<VALUE>45</VALUE>
</row>
<row TYPE="CDS">
<GROUP>Multis</GROUP>
<VALUE>78</VALUE>
</row>
</VARIABLE>
</DATA>
Invoke
DECLARE #tblItems table (
[TYPE] varchar(50)
,[GROUP] varchar(50)
,[VALUE] int
)
DECLARE #tblShredded table (
[TYPE] varchar(50)
,[XmlItem] xml
)
DECLARE #xmlGroupValueTuples xml
insert into #tblItems([TYPE],[GROUP],[VALUE]) values( 'Books','Hardback',56)
insert into #tblItems([TYPE],[GROUP],[VALUE]) values( 'Books','Softcover',34)
insert into #tblItems([TYPE],[GROUP],[VALUE]) values( 'CDs','Singles',45)
insert into #tblItems([TYPE],[GROUP],[VALUE]) values( 'CDS','Multis',78)
SET #xmlGroupValueTuples =
(
SELECT
"#TYPE" = [TYPE]
,[GROUP]
,[VALUE]
FROM #tblItems
FOR XML PATH('row'), root('Root')
)
INSERT #tblShredded([TYPE], XmlItem)
SELECT
[TYPE] = XmlItem.value('./row[1]/#TYPE', 'varchar(50)')
,XmlItem
FROM dbo.tvfShredGetOneColumnedTableOfXmlItems(#xmlGroupValueTuples)
SELECT
(
SELECT
VARIABLE =
(
SELECT
"#TYPE" = t.[TYPE]
,(
SELECT
tInner.XmlItem.query('./child::*')
FROM #tblShredded tInner
WHERE tInner.[TYPE] = t.[TYPE]
FOR XML PATH(''), ELEMENTS, type
)
FOR XML PATH('VARIABLE'),type
)
)
FROM #tblShredded t
GROUP BY
t.[TYPE]
FOR XML PATH(''), ROOT('DATA')
where
-- Example Inputs
/*
DECLARE #xmlListFormat xml
SET #xmlListFormat =
'
<XmlListRoot>
<Item>004421UB7</Item>
<Item>59020UH24</Item>
<Item>542514NA8</Item>
</XmlListRoot>
'
*/
-- =============================================
-- Author: 6eorge Jetson
-- Create date: 01/22/3003
-- Description: Shreds an input XML list conforming to the expected list schema
-- =============================================
CREATE FUNCTION [dbo].[tvfShredGetOneColumnedTableOfXmlItems] (#xmlListFormat xml)
RETURNS
#tblResults TABLE (XmlItem xml)
AS
BEGIN
INSERT #tblResults
SELECT
tblShredded.colXmlItem.query('.') as XmlItem
FROM
#xmlListFormat.nodes('/child::*/child::*') as tblShredded(colXmlItem)
RETURN
END