SQL Table result in a xml output - sql

I have a table
Key code
1 100
1 200
1 300
1 400
2 100
2 200
2 300
I am looking for my result in one row with key and other row XML_data
Key XML_Data(XML column)
1 <sub><key>1...
2 <sub><key>2...
XML_Data example :
<sub>
<key> 1 </Key>
<list>
<code> 100 </code>
<code> 200 </code>
<code> 300 </code>
<code> 400 </code>
</list>
</sub>
Thanks

I think that this SQL Server: Two-level GROUP BY with XML output it's closer.
Posted here because i don't have reputation for comment.

Your question is quite fuzzy, but my magic crystall ball tells me, that you are looking for this:
DECLARE #tbl TABLE([Key] INT, code INT);
INSERT INTO #tbl VALUES
(1,100)
,(1,200)
,(1,300)
,(1,400)
,(2,100)
,(2,200)
,(2,300);
--The query will first find a distinct list of keys and then use nested FOR XML-selects to gather your data into the structure wanted:
WITH DistinctKeys AS
(SELECT [Key] FROM #tbl GROUP BY [Key])
SELECT dk.[Key]
,(
SELECT dk.[Key]
,(
SELECT t.code
FROM #tbl AS t
WHERE t.[Key]=dk.[Key]
FOR XML PATH(''),ROOT('list'),TYPE
)
FOR XML PATH('sub'),TYPE
) AS XML_Data
FROm DistinctKeys AS dk
The result
Key XML_Data
1 <sub><Key>1</Key><list><code>100</code><code>200</code><code>300</code><code>400</code></list></sub>
2 <sub><Key>2</Key><list><code>100</code><code>200</code><code>300</code></list></sub>

You've not specified much, as to where your XML is etc. but in general following query should help in your case.
INSERT INTO dbo.YourTable
(key, xml_data)
VALUES
(KEY, CONVERT(XML, N'YOUR_XML', 2));
You can go even further with that, by declaring XML as variable, extracing your KEY from XML, and to 2nd column adding XML based on whole variable.
DECLARE #input XML = '<sub>
<key> 1 </key>
<list>
<code> 100 </code>
<code> 200 </code>
<code> 300 </code>
<code> 400 </code>
</list>
</sub>'
INSERT INTO dbo.YourTable(key, xml_data)
SELECT
key = COALESCE(XCol.value('key[1]', 'int'),0),
xml_data = CONVERT(XML, N''''+#input+'''', 2)
FROM #input.nodes('/sub') AS XTbl(XCol)
#ATC, thank you for your comment. If really what is needed is to get table into XML format please try following - FOR XML PATH is what you're looking for
SELECT
key,
code as "list/code"
FROM dbo.YourTable
FOR XML PATH('sub')
I'm not able to test it right now unfortunately.
Here you can see similar question: How to convert records in a table to xml format using T-SQL?

Related

Select 2nd row in XML Column in database using SQL

Having trouble selecting a specific info from an XML Format in a column of a table in the database. I need to pull the Success message for ModuleID 959
SubmissionID
ModuleID
CreatedOn
XMLCOL
UpdatedOn
25
959
1-1-22
"see XML below"
1-1-22
26
339
2-1-22
Null
2-1-22
Below is the data inside the XML column within the database - what I want to achieve is to show the 2nd ResultType "success" in the query with SQL.
<ArrayOfActionResult xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<ActionResult>
<ResultType>Redirected to Payment</ResultType>
<ActionName>Payment</ActionName>
<ExecutionTime></ExecutionTime>
<ConditionSet>
<Conditions />
<ExecuteCondition>Always</ExecuteCondition>
<MatchCondition>All</MatchCondition>
<ExecuteStatus>0</ExecuteStatus>
<Groups />
</ConditionSet>
<ConditionsMet>true</ConditionsMet>
<Condition />
</ActionResult>
<ActionResult>
<ResultType>Success</ResultType>
<ActionName>Payment</ActionName>
<ExecutionTime></ExecutionTime>
<ConditionSet>
<Conditions />
<ExecuteCondition>Always</ExecuteCondition>
<MatchCondition>All</MatchCondition>
<ExecuteStatus>0</ExecuteStatus>
<Groups />
</ConditionSet>
<ConditionsMet>true</ConditionsMet>
</ActionResult>
</ArrayOfActionResult>
Currently I'm trying to use the SQL below to no avail
SELECT [XMLCOL].value('/ArrayOfActionResult/ActionResult/ResultType[2]') as PaymentMessage
FROM Databasetable
where [ModuleID] = 959
Hopefully this makes sense, I found it quite difficult to explain, I am very new to SQL
Check it out below.
Assuming your db is MS SQL Server.
The XQuery .value() method has two mandatory parameters.
SQL
-- DDL and sample data population, start
DECLARE #tbl TABLE (ModuleID INT PRIMARY KEY, XMLCOL XML);
INSERT INTO #tbl (ModuleID, XMLCOL) VALUES
(959, N'<ArrayOfActionResult xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<ActionResult>
<ResultType>Redirected to Payment</ResultType>
<ActionName>Payment</ActionName>
<ExecutionTime></ExecutionTime>
<ConditionSet>
<Conditions/>
<ExecuteCondition>Always</ExecuteCondition>
<MatchCondition>All</MatchCondition>
<ExecuteStatus>0</ExecuteStatus>
<Groups/>
</ConditionSet>
<ConditionsMet>true</ConditionsMet>
<Condition/>
</ActionResult>
<ActionResult>
<ResultType>Success</ResultType>
<ActionName>Payment</ActionName>
<ExecutionTime></ExecutionTime>
<ConditionSet>
<Conditions/>
<ExecuteCondition>Always</ExecuteCondition>
<MatchCondition>All</MatchCondition>
<ExecuteStatus>0</ExecuteStatus>
<Groups/>
</ConditionSet>
<ConditionsMet>true</ConditionsMet>
</ActionResult>
</ArrayOfActionResult>');
-- DDL and sample data population, end
SELECT ModuleID
, XMLCOL.value('(/ArrayOfActionResult/ActionResult[2]/ResultType/text())[1]','VARCHAR(30)') as PaymentMessage
FROM #tbl
WHERE ModuleID = 959;
Output
+----------+----------------+
| ModuleID | PaymentMessage |
+----------+----------------+
| 959 | Success |
+----------+----------------+

XML Output from SQL Server 2008

I am trying to create an XML output from SQL that has 3 nested statements but have pretty minimal experience in this area. The code I've written is below:
select
replace(replace(replace(
(
select ID as [#ID],
(select cast(Name as int) as [#Name],
(select num as [#Number],
from #tbl_new_claims_export
for xml path('Num'),root('Numbers'), type
)
from #tbl_new_claims_export
for xml path('LineItem'), type
)
from #tbl_new_claims_export
for XML PATH('Line'),ROOT('Lines')
),'><','>'+char(10)+'<'),'<Num', char(9)+'<Num'), '<Num>', char(9)+'<Num>') ;
I am trying to create an output that looks like this:
<Lines>
<Line ID ="1">
<LineItem Name ="Michael"/>
<Numbers>
<Num Number="24"</Num>
</Numbers>
</LineItem>
</Line>
For each Line, I want to see the Line, Name, and Number as shown above. However, it is showing multiple Names under each Line and then repeats the Number below. Can anybody help me troubleshoot this code?
Thanks.
Without sample data with 1:n examples and the expected output it is reading in the magic glass bulb...
Anyway, this
SELECT
1 AS [Line/#ID]
,'Michael' AS [LineItem/#Name]
,24 AS [Numbers/Num/#Number]
FOR XML PATH('Lines')
will produce exactly the output you specify:
<Lines>
<Line ID="1" />
<LineItem Name="Michael" />
<Numbers>
<Num Number="24" />
</Numbers>
</Lines>
If you need further help, please specify a minimal and reduced test scenario. Best would be a fiddle or some pasteable code like
DECLARE #tbl TABLE(ID INT, col1 VARCHAR(MAX)/*more columns*/);
INSERT INTO #tbl VALUES (1,'test1')/*more values*/

SQL Query Column with XML Data

I have the following data in a column, how can I query the values inside.
<deliveryPart notificationId="12345">
<message address="email#email.com" content="multipart/alternative" domain="email.com" format="0" id="159436637" recipient-id="098765" targetCode="__MAIN__">
<custom>
<recipient Nickname="mynickname" id="54321" />
<targetData Incident_Id="1509403" reference_nb="0000-0000" />
</custom>
</message>
</deliveryPart>
I gave it a quick go but I've never done it before and I am in short of time.
select top 10 *
from [db].[db].[table]
where mData.value('(deliveryPart/message/recipient-id)[1]','varchar(max)') like '098765'
I get the following error
Msg 4121, Level 16, State 1, Line 1
Cannot find either column "mData" or the user-defined function or aggregate "mData.value", or the name is ambiguous.
UPDATE
I am using the following code to fetch the xml values and it works
SELECT TOP 1000 B1.[mData].value('(deliveryPart/message/#id)[1]', 'NVARCHAR(MAX)') AS 'MessageID', B1.[mData].value('(deliveryPart/message/#address)[1]', 'NVARCHAR(MAX)') AS 'Address'
FROM (SELECT CAST(mData as XML) as xmlData FROM [dbo].[db].[table]) B0
CROSS APPLY xmlData.nodes('/') B1 (mData)
WHERE B1.[mData].value('(deliveryPart/message/#address)[1]', 'NVARCHAR(MAX)') LIKE '%#%'
And it returns the xml values store in the ntext field just fine.
180646774 email1#email.com
159436627 test2#hotmail.com
159436637 test3#hotmail.com
However, I need to fetch values from outside the mData column and is not letting me do it.
You need to use the #recipient-id as a XML attribute - not XML element:
<message address="email#email.com" content="multipart/alternative"
domain="email.com" format="0" id="159436637"
recipient-id="098765" targetCode="__MAIN__">
************ this is an *attribute* - use the `#` to select it!
Code:
select top 10 *
from [db].[db].[table]
where mData.value('(deliveryPart/message/#recipient-id)[1]', 'varchar(max)') like '098765'

Selecting columns as XML with namespace

I need to select some columns from a table as XML with namespaces included in them along with other columns as is. For example, I have a following table layout:
ID C1 X1C1 X1C2 X2C3
1 A 1 2 3
What the query should return is:
ID C1 XmlData
1 A <xmldata1>
2 A <xmldata2>
Where <xmldata1> would be:
<Root xmlns:xsd="w3.org/2001/XMLSchema" xmlns:xsi="w3.org/2001/XMLSchema-instance" xmlns:mst="microsoft.com/wsdl/types/">
<Child attrib="C1">
<ChildValue xsi:type="xsd:integer">1</ChildNode>
</Child>
<Child attrib="C2">
<ChildNode xsi:type="xsd:integer">2</ChildNode>
</Child>
</Root>
and <xmldata2> would be:
<Rootxmlns:xsd="w3.org/2001/XMLSchema" xmlns:xsi="w3.org/2001/XMLSchema-instance" xmlns:mst="microsoft.com/wsdl/types/">
<Child attrib="C3">
<ChildNode xsi:type="xsd:integer">3</ChildNode>
</Child>
</Root>
I have a good reference how to build the xml from this SO question but I'm not able to put in the namespaces. If this is possible how to do it?
Edit:
I've used following query attempting to get the required result:
select 1 ID, 'A' C1, 1 X1C1, 2 X1C2, 3 X2C3
into #t
;with xmlnamespaces('w3.org/2001/XMLSchema' as xsd, 'w3.org/2001/XMLSchema-instance' as xsi, 'microsoft.com/wsdl/types/' as mst)
select ID, C1, (select (SELECT 'C1' "#attrib", 'xsd:integer' "ChildValue/#xsi:type",t.X1C1 as 'ChildValue' FOR XML PATH('Child'), type),(SELECT 'C2' "#name", 'xsd:integer' "ChildValue/#xsi:type", t.X1C2 as 'ChildValue' FOR XML PATH('Child'), type) FOR XML PATH('Root'), type) as property_data
FROM #t t
drop table #t
Here is the output of its xml part:
<Root xmlns:mst="microsoft.com/wsdl/types/" xmlns:xsi="w3.org/2001/XMLSchema-instance" xmlns:xsd="w3.org/2001/XMLSchema">
<Child xmlns:mst="microsoft.com/wsdl/types/" xmlns:xsi="w3.org/2001/XMLSchema-instance" xmlns:xsd="w3.org/2001/XMLSchema" attrib="C1">
<ChildValue xsi:type="xsd:integer">1</ChildValue>
</Child>
<Child xmlns:mst="microsoft.com/wsdl/types/" xmlns:xsi="w3.org/2001/XMLSchema-instance" xmlns:xsd="w3.org/2001/XMLSchema" name="C2">
<ChildValue xsi:type="xsd:integer">2</ChildValue>
</Child>
</Root>
I can't get rid of the namespaces in the Child node.
I used this solution: TSQL for xml add schema attribute to root node
Basically, I did not put the namespace in the beginning but after generating the required xml structure I casted the xml to nvarchar(max) and replaced the root node with the desired namespace.
I also needed to use namespace prefix in the attribute. For that I used a pseudo attribute name which I replaced with a proper xml namespace prefix.
Both operations were done using tsql REPLACE function. Hacky but couldn't find other proper ways to do it.
you need to include WITH xmlnamespaces , example:
;with xmlnamespaces('w3.org/2001/XMLSchema' as xsd, 'w3.org/2001/XMLSchema-instance' as xsi, 'microsoft.com/wsdl/types/' as mst)
select ID, C1,
(select
(SELECT 'C1' "#name",t.C1 as 'value'FOR XML PATH('Property'), type),
(SELECT 'C2' "#name",t.C2 as 'value'FOR XML PATH('property'), type)
FOR XML PATH('data'), type) as property_data
FROM TableName t
Have you tried like?
select XML_COL_NAME.value('(/rootNode//childNode/node())[1]', 'nvarchar(64)') from tableName

XML parsing using SQL Server

I need to parse the XML below, however the values generated is wrong. Anyone has an idea?
Results
Code Pay1_515
5570, Industry1, 1 10
5570, Industry2, 2 10
Sample XML
DECLARE #XML xml = '<?xml version="1.0" encoding="utf-8"?>
<CookedData>
<Column DestinationColumnCode="Code">
<r v="5570, Industry1, 1" />
<r v="5570, Industry2, 2" />
</Column>
<Column DestinationColumnCode="Pay1_515">
<r v="10" />
<r v="10" />
</Column>
</CookedData>';
Sample code
with C as
(
select T.X.value('(Column[#DestinationColumnCode = "Code"]/r/#v)[1]', 'NVARCHAR(3000)') as Code,
T.X.value('(Column[#DestinationColumnCode = "Pay1_515"]/r/#v)[1]', 'NVARCHAR(3000)') as Pay
from #XML.nodes('/CookedData/Column') as T(X)
)
SELECT * FROM C
Try this:
with C as
(
select T.X.value('(//Column[#DestinationColumnCode = "Code"]/r/#v)[1]', 'NVARCHAR(3000)') as Code,
T.X.value('(//Column[#DestinationColumnCode = "Pay1_515"]/r/#v)[1]', 'NVARCHAR(3000)') as Pay
from #XML.nodes('/CookedData/Column') as T(X)
You need to use this:
SELECT
Code = T.X.value('#DestinationColumnCode', 'VARCHAR(30)'),
RValue= r.value('#v', 'varchar(50)')
FROM
#XML.nodes('/CookedData/Column') as T(X)
CROSS APPLY
X.nodes('r') AS T2(R)
This will produce the output:
This has been bugging me all morning. I wondered if I could improve on the answer given by #marc_s (to the detriment of my actual work :-/) and I have managed to get the required output. However, some caveats:
This assumes that the order of child r nodes in each Column node correlates to the other (i.e. the first r node in each should be side by side and so on). This is because there is no other way to tie them together that I can see.
It's not very generic - as it stands, it won't work for n columns without extra code and fiddling about.
You don't mind some pretty filthy code which is likely to be pretty poor performing on large amounts of data (even with some tuning - my brain has now melted and can't cope with any more fiddling on it).
I've tested with a few more rows in the XML but I would not guarantee it's efficacy in all cases, it would need some serious testing.
I couldn't be bothered to get the final column names right.
Someone, anyone, please feel free to improve this, but FWIW here it is (complete, working code):
DECLARE #XML xml = '<?xml version="1.0" encoding="utf-8"?>
<CookedData>
<Column DestinationColumnCode="Code">
<r v="5570, Industry1, 1" />
<r v="5570, Industry2, 2" />
</Column>
<Column DestinationColumnCode="Pay1_515">
<r v="10" />
<r v="10" />
</Column>
</CookedData>';
DECLARE #shredXML TABLE (Code VARCHAR(10), RValue VARCHAR(20))
DECLARE #Codes TABLE (RowNum INT, ColCode VARCHAR(10))
--Do this once at the start and use the results.
INSERT INTO #shredXML
SELECT
Code = T.X.value('#DestinationColumnCode', 'VARCHAR(30)'),
RValue= r.value('#v', 'varchar(50)')
FROM
#XML.nodes('/CookedData/Column') as T(X)
CROSS APPLY
X.nodes('r') AS T2(R)
--First get the distinct list of DestinationColumnCode values.
INSERT INTO #Codes
SELECT ROW_NUMBER() OVER (ORDER BY colcodes.Code), colcodes.Code
FROM #shredXML colcodes
GROUP BY colcodes.Code
SELECT p1.RValue, p2.RValue
FROM (
--Get all the values for the code column
SELECT ROW_NUMBER() OVER (ORDER BY Codes.RValue) AS RowNum, Codes.RValue, Codes.Code
FROM (
SELECT x.Code, x.RValue FROM #shredXML x
INNER JOIN #Codes c
ON c.ColCode = x.Code
WHERE c.RowNum = 1) AS Codes) AS p1
--Join the values column on RowNum
INNER JOIN (
SELECT ROW_NUMBER() OVER (ORDER BY Vals.RValue) AS RowNum, Vals.RValue, Vals.Code
FROM (
SELECT x.Code, x.RValue FROM #shredXML x
INNER JOIN #Codes c
ON c.ColCode = x.Code
WHERE c.RowNum = 2) AS Vals) AS p2
ON p1.RowNum = p2.RowNum
EDIT
Finally got SQLFiddle to play ball and run the example above