Import XML to SQL table and format data - sql

Would someone be able to help me I am trying to import an xml file to a sql server table. I can import the required data but having some trouble getting it in the format required.
declare #input XML = '<Sub>
<Results>
<Result>
<ids>
<id>
<type>code</type>
<value>9004a3d2</value>
</id>
<id>
<type>username</type>
<value>jbloggs001</value>
<date>20160725</date>
</id>
<id>
<type>EmployeeID</type>
<value>01234</value>
<date>20160725</date>
</id>
</ids>
</Result>
</Results>
</Sub>'
SELECT
datatype = XCol.value('(type)[1]','varchar(25)'),
datavalue = XCol.value('(value)[1]','varchar(50)')
FROM
#input.nodes('/Sub/Results/Result/ids/id') AS XTbl(XCol)
This gives 3 columns like:
datatype datavalue
--------------------------------
code 9004a3d2
username jbloggs001
employeeID 01234
Would it be possible to get it to import as?
EmployeeID USername Code
---------------------------------
01234 jbloggs 0019004a3d2
Thanks

As was suggested in comments that could be done using PIVOT:
SELECT *
FROM (
SELECT
datatype = XCol.value('(type)[1]','varchar(25)'),
datavalue = XCol.value('(value)[1]','varchar(50)')
FROM
#input.nodes('/Sub/Results/Result/ids/id') AS XTbl(XCol)
) as p
PIVOT (
MAX(datavalue) FOR datatype IN (EmployeeID,username,code)
) as pvt
Output:
EmployeeID username code
01234 jbloggs001 9004a3d2
If input is always with same types:
SELECT XCol.value('(id/value)[3]','varchar(50)') as EmployeeID,
XCol.value('(id/value)[2]','varchar(50)') as username,
XCol.value('(id/value)[1]','varchar(50)') as code
FROM #input.nodes('/Sub/Results/Result/ids') AS XTbl(XCol)

Another option is XQuery contains function
declare #input XML = '<Sub>
<Results>
<Result>
<ids>
<id>
<type>code</type>
<value>9004a3d2</value>
</id>
<id>
<type>username</type>
<value>jbloggs001</value>
<date>20160725</date>
</id>
<id>
<type>EmployeeID</type>
<value>01234</value>
<date>20160725</date>
</id>
</ids>
</Result>
</Results>
</Sub>';
SELECT
code = XCol.value('(id[contains((./type)[1],"code")]/value)[1]','varchar(50)'),
username = XCol.value('(id[contains((./type)[1],"username")]/value)[1]','varchar(50)'),
EmployeeID = XCol.value('(id[contains((./type)[1],"EmployeeID")]/value)[1]','varchar(50)')
FROM
#input.nodes('/Sub/Results/Result/ids') AS XTbl(XCol);

Below query works for your solution
Select [EmployeeID],[Username],[Code]
FROM #TEMP
PIVOT
(
MAX(DATAVALUE) FOR DATATYPE IN (code,username,employeeID)
)A

Another very straight and typesafe approach was this:
SELECT id.value('(id[type="code"]/value)[1]','varchar(max)') AS code
,id.value('(id[type="username"]/value)[1]','varchar(max)') AS username
,id.value('(id[type="EmployeeID"]/value)[1]','varchar(max)') AS EmployeeID
FROM #input.nodes('Sub/Results/Result/ids') AS A(id)

Related

T-SQL, get value from xml in a column

I have a table with an XML column (xmlCol) and I am trying to query a value from it.
Here's the xml.
<criteria>
<factor name="Rivers" title="Rivers">
<value dataType="Int32" value="1743" description="Wilson0" />
</factor>
<factor name="OptionalAffProperties" title="Include properties">
<value dataType="String" value="FishingModel" description="Fishing Model" />
</factor>
</criteria>
Here is a select to get the column. select xmlCol from MyTable
I am trying to return the value 1743 to a column called RiverID.
Mike
This should work:
SELECT
xmlCol.value('(//factor[#name="Rivers"]/value/#value)[1]', 'int') As RiverID
FROM
MyTable
value() Method (xml Data Type) - SQL Server | Microsoft Docs
XQuery Language Reference (SQL Server) - SQL Server | Microsoft Docs
To get the attribute value, you can query it like so:
select xmlCol.value('(/criteria/factor/value/#value)[1]', 'int') RiverID
from MyTable
You provide the xml path to the record you are looking for: (/criteria/factor/value
And then the attribute you need: /#value)[1].

Query xml using xquery in SQL Server 2016

I have my XML in following format:
<resultset xmlns="qm_system_resultset" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<result>
<result_id>F5</result_id>
<exception>NO</exception>
<recurring_count>0</recurring_count>
<defect>NO</defect>
<unresolved>NO</unresolved>
<exception_approval />
<comments />
<exception_expiration>3000-01-01</exception_expiration>
<exception_stat_only>NO</exception_stat_only>
<result_data>
<phraseprefix>rx</phraseprefix>
<phrasenumber>0001</phrasenumber>
<languagedesc>Khmer</languagedesc>
<englishphrase> each time.</englishphrase>
<phrasedesc> គ្រាប់ក្នុងមួយដង។</phrasedesc>
<qm_translatedphrase>day.</qm_translatedphrase>
</result_data>
</result>
<result>
<result_id>26</result_id>
<exception>NO</exception>
<recurring_count>0</recurring_count>
<defect>NO</defect>
<unresolved>NO</unresolved>
<exception_approval />
<comments />
<exception_expiration>3000-01-01</exception_expiration>
<exception_stat_only>NO</exception_stat_only>
<result_data>
<phraseprefix>hold</phraseprefix>
<phrasenumber>0001</phrasenumber>
<languagedesc>Hmong</languagedesc>
<englishphrase>Hold than 160.</englishphrase>
<phrasedesc>Tsis 160.</phrasedesc>
<qm_translatedphrase>Do not use </qm_translatedphrase>
</result_data>
</result>
Using TSQL/XML query how do I achieve this RESULT
[phraseprefix][phrasenumber]
rx 0001
hold 0001
...
I tried the following query, but I got null values for both the columns:
DECLARE #input XML = (SELECT result_xml
FROM QM_Data_Audit.QM_Package.test_results
WHERE result_id = 2446338)
SELECT
resultset.value('(phraseprefix)[1]', 'varchar(max)') AS 'phrasenumber',
resultset.value('(phrasenumber)[1]', 'int') AS 'phrasenumber'
FROM #input.nodes('/resultset/result/result_data') AS List(resultset)
My apologies if the question is asked previously, I am new to querying XML.
Appreciate your help.
Your xml has a namespace declared so you need to provide this when querying it. In this example this can be acheived with the WITH XMLNAMESPACES statement:
DECLARE #input XML = (SELECT result_xml
FROM QM_Data_Audit.QM_Package.test_results
WHERE result_id = 2446338);
WITH XMLNAMESPACES(DEFAULT 'qm_system_resultset')
SELECT
resultset.value('(phraseprefix)[1]', 'varchar(max)') AS 'phrasenumber',
resultset.value('(phrasenumber)[1]', 'varchar(max)') AS 'phrasenumber'
FROM #input.nodes('/resultset/result/result_data') AS List(resultset)
You'll want to set the data type for phrasenumber to varchar as well to preserve the leading 0s if you need them.

SQL Table result in a xml output

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?

TSQL XML Parsing and creating xml

I have a tool which I now will be creating reports for using the data I have. I am currently working on a year to date report and need to pull the numbers for that.
My goal is to have an XML output of each of the months in the current year with their totals.
Here is what the XML currently looks like with my select statement:
<root>
<data>
<classXML>
<courses>
<class>
<classTitle>Arts and Crafts</classTitle>
<tuitionCost>100</tuitionCost>
<bookCost>30</bookCost>
<classTotal>130</classTotal>
</class>
<class>
<classTitle>Paper 101</classTitle>
<tuitionCost>320</tuitionCost>
<bookCost>211</bookCost>
<classTotal>531</classTotal>
</class>
<class>
<classTitle>Introduction to Pencils</classTitle>
<tuitionCost>210</tuitionCost>
<bookCost>291</bookCost>
<classTotal>501</classTotal>
</class>
<class>
<classTitle>Intermediate Folding</classTitle>
<tuitionCost>110</tuitionCost>
<bookCost>22</bookCost>
<classTotal>132</classTotal>
</class>
<class>
<classTitle>Advanced Jumprope</classTitle>
<tuitionCost>11</tuitionCost>
<bookCost>22</bookCost>
<classTotal>33</classTotal>
</class>
<grandTotal>1327</grandTotal>
</courses>
</classXML>
<reimbursementDate>08/01/2014</reimbursementDate>
</data>
<data>
<classXML>
<courses>
<class>
<classTitle>dsfgfdsg</classTitle>
<tuitionCost>44</tuitionCost>
<bookCost>44</bookCost>
<classTotal>88</classTotal>
</class>
<grandTotal>88</grandTotal>
</courses>
</classXML>
<reimbursementDate>05/31/2014</reimbursementDate>
</data>
</root>
And my stored procedure:
SELECT
A.[classXML],
CONVERT(VARCHAR(10), A.[reimbursementDate], 101) as reimbursementDate
FROM
tuitionSubmissions as A
WHERE
A.[status] = 'Approved'
AND YEAR(A.[reimbursementDate]) = YEAR(GETDATE())
FOR XML PATH ('data'), TYPE, ELEMENTS, ROOT ('root');
As you can see, the column classXML stores that data in XML format with all of the classes they are enrolled in with their costs.
So I need to loop over the XML and create an output that is just numbers to assist with my reporting.
Here is my desired outcome:
<results>
<dataSet>
<month>8</month>
<year>2014</year>
<tuitionTotal>500</tuitionTotal>
<booksTotal>200</booksTotal>
<grandTotal>700</grandTotal>
</dataSet>
<dataSet>
<month>9</month>
<year>2014</year>
<tuitionTotal>100</tuitionTotal>
<booksTotal>500</booksTotal>
<grandTotal>600</grandTotal>
</dataSet>
</results>
You can use sum Function (XQuery) to do the aggregation against your XML column.
I put the query against the XML in a cross apply so you don't have to do the same XQuery twice just to calculate grandTotal.
You should also change your predicate against reimbursementDate so it may use and index to find the rows.
select datepart(month, T.reimbursementDate) as month,
datepart(year, T.reimbursementDate) as year,
S.tuitionTotal,
S.booksTotal,
S.tuitionTotal + S.booksTotal as grandTotal
from dbo.tuitionSubmissions as T
cross apply (
select T.classXML.value('sum(/courses/class/tuitionCost/text())', 'int') as tuitionTotal,
T.classXML.value('sum(/courses/class/bookCost/text())', 'int') as booksTotal
) as S
where T.status = 'Approved' and
T.reimbursementDate >= '20140101' and
T.reimbursementDate < '20150101'
for xml path('dataSet'), root('results'), type
SQL Fiddle
DECLARE #DocH INT
DECLARE #DOC XML = '
<root>
<data>
<classXML>
<courses>
<class>
<classTitle>Arts and Crafts</classTitle>
<tuitionCost>100</tuitionCost>
<bookCost>30</bookCost>
<classTotal>130</classTotal>
</class>
<class>
<classTitle>Paper 101</classTitle>
<tuitionCost>320</tuitionCost>
<bookCost>211</bookCost>
<classTotal>531</classTotal>
</class>
<class>
<classTitle>Introduction to Pencils</classTitle>
<tuitionCost>210</tuitionCost>
<bookCost>291</bookCost>
<classTotal>501</classTotal>
</class>
<class>
<classTitle>Intermediate Folding</classTitle>
<tuitionCost>110</tuitionCost>
<bookCost>22</bookCost>
<classTotal>132</classTotal>
</class>
<class>
<classTitle>Advanced Jumprope</classTitle>
<tuitionCost>11</tuitionCost>
<bookCost>22</bookCost>
<classTotal>33</classTotal>
</class>
<grandTotal>1327</grandTotal>
</courses>
</classXML>
<reimbursementDate>08/01/2014</reimbursementDate>
</data>
<data>
<classXML>
<courses>
<class>
<classTitle>dsfgfdsg</classTitle>
<tuitionCost>44</tuitionCost>
<bookCost>44</bookCost>
<classTotal>88</classTotal>
</class>
<grandTotal>88</grandTotal>
</courses>
</classXML>
<reimbursementDate>05/31/2014</reimbursementDate>
</data>
</root>'
EXEC sp_xml_preparedocument #DocH OUTPUT, #DOC
SELECT
MONTH(reimbursementDate) AS month
, YEAR(reimbursementDate) AS year
, SUM(tuitionCost) AS tuitionTotal, SUM(bookCost) AS bookTotal, SUM(tuitionCost+bookCost) AS grandTotal
FROM OPENXML(#DocH,'/root/data/classXML/courses/class') WITH (
classTitle varchar(40) 'classTitle'
, tuitionCost INT 'tuitionCost'
, bookCost INT 'bookCost'
, reimbursementDate date '../../../reimbursementDate'
)
GROUP BY MONTH(reimbursementDate)
, YEAR(reimbursementDate)
FOR XML PATH ('dataset')
EXEC sp_xml_removedocument #DocH;

sql to extraction xml form column

This is the sample of xml in my table column;
Table name t005, column name ACTIVITYDETAIL, data type xml.
Sample of xml
<root>
<Parameter>
<Param>SearcgBy</Param>
<Value>ALL</Value>
</Parameter>
<Parameter>
<Param>SearchText</Param>
<Value>SA</Value>
</Parameter>
</root>
Now I want output as
Param value
SearchBy ALL
SearchText SA
I tried so many ways and here is my last try.
SELECT
p.value('(./Parameter/node())[1]', 'VARCHAR(8000)') as firstName,
p.value('(./Parameter/node())[2]', 'VARCHAR(8000)') as lastName
FROM
t005
CROSS APPLY
ACTIVITYDETAIL.nodes('/root') t(p)
Please help me.
Try this
SELECT
t.p.value('Param[1]','varchar(20)') as Param,
t.p.value('Value[1]','varchar(20)') as Value
FROM T005 CROSS APPLY ACTIVITYDETAIL.nodes('/root/Parameter') t(p)