Parsing XML data in SQL with attribute - sql-server

I currently have an XML I am pulling from a column in SQL formatted like this:
<Datas>
<CHILD value="test" />
</Datas>
I need a way to grab the value in the CHILD tag but I am having some issues I believe to be stemming from it being a self closing tag. I am able to get the data if it was formatted in this format:
<Datas>
<CHILD>test</CHILD>
</Datas>
However, this format is not an option as the application I'm pulling from does not store it this way.
I have tried the following SQL:
select cast(xmlField as xml) xmlField into tmp from (
select '<Datas><CHILD value = "test"/></Datas>' xmlField
) tb
SELECT
xmlField.value('(Datas/CHILD)[1]', 'nvarchar(max)') as Data
FROM tmp
drop table tmp
Any help is greatly appreciated. Thanks!

The problem isn't that it's self closing, it's that you want to access an attribute. For those you need to use the attribute's name prefixed with an #:
SELECT xmlField.value('(Datas/CHILD/#value)[1]', 'nvarchar(max)') AS Data
FROM tmp;

Related

How to store XML data list in a table

Im working on a script that will allow me to save the xml data in a table. This will be used to compare with other tables which also contains an xml data.
I've been successful so far for simple node tags, but have encountered an issue when trying to store the data from a list.
The XML data looks like this:Sample XML Data
And my query is this:
XML Query display
I am able to get the 'TypeCode' as the main node but for the value, it's always showing blank. I'm not sure how to handle the list in XML.
I'm thinking as long as I can save the data
''
'' as text in the Value column, then I can find another way to parse it and display it in a nicer way as another query.
Any help is appreciated :D Thanks!
For your next question: Please do not post pictures. I had to type this in... Please provide consumable data, best as a stand-alone example to reproduce your issue.
DECLARE #xml XML=
'<Codes>
<TypeCodes type="list">
<item key="A" text="A1"/>
<item key="C" text="C1"/>
</TypeCodes>
</Codes>';
--the Xml "as is"
SELECT #xml;
--fetch one value with XQuery
SELECT #xml.value('(/Codes/TypeCodes/item[#key="A"]/#text)[1]','varchar(10)');
--fetch all items as list
SELECT #xml.value('(/Codes/TypeCodes/#type)[1]','varchar(10)') AS TypeCode_type
,i.value('#key','varchar(10)') AS item_key
,i.value('#text','varchar(10)') AS item_text
FROM #xml.nodes('/Codes/TypeCodes/item') A(i);
check it out
Good day,
SQL Server include special data type XML which is what you should use in order to store your XML data.
declare #MyXML XML = '
<codes>
<Type>
<Item key="1" />
</Type>
</codes>
'
select #MyXML
Here is example of using table:
DROP TABLE IF eXISTS T;
CREATE TABLE T(MyXML XML)
GO
INSERT T(MyXML) values ('
<codes>
<Type>
<Item key="1" />
</Type>
</codes>
')
SELECT * FROM T
GO
For more information check this documentation:
XML Data Type and Columns (SQL Server)

Extracting XML in a column from a SQL Server database

I have read dozens of posts and have tried numerous SQL queries to try and get this figured out. Sadly, I'm not a SQL expert (not even a novice) nor am I an XML expert. I understand basic queries from SQL, and understand XML tags, mostly.
I'm trying to query a database table, and have the data show a list of values from a column that contains XML. I'll give you an example of the data. I won't burden you with everything I have tried.
Here is an example of field inside of the column I need. So this is just one row, I would need to query the whole table to get all of the data I need.
When I select * from [table name] it returns hundreds of rows and when I double click in the column name of 'Document' on one row, I get the information I need.
It looks like this:
<code_set xmlns="">
<name>ExampleCodeTable</name>
<last_updated>2010-08-30T17:49:58.7919453Z</last_updated>
<code id="1" last_updated="2010-01-20T17:46:35.1658253-07:00"
start_date="1998-12-31T17:00:00-07:00"
end_date="9999-12-31T16:59:59.9999999-07:00">
<entry locale="en-US" name="T" description="Test1" />
</code>
<code id="2" last_updated="2010-01-20T17:46:35.1658253-07:00"
start_date="1998-12-31T17:00:00-07:00"
end_date="9999-12-31T16:59:59.9999999-07:00">
<entry locale="en-US" name="Z" description="Test2" />
</code>
<displayExpression>[Code] + ' - ' + [Description]</displayExpression>
<sortColumn>[Description]</sortColumn>
</code_set>
Ideally I would write it so it runs the query on the table and produces results like this:
Code Description
--------------------
(Data) (Data)
Any ideas? Is it even possible? The dozens of things I have tried that are always posted in stack, either return Nulls or fail.
Thanks for your help
Try something like this:
SELECT
CodeSetId = xc.value('#id', 'int'),
Description = xc.value('(entry/#description)[1]', 'varchar(50)')
FROM
dbo.YourTableNameHere
CROSS APPLY
YourXmlColumn.nodes('/code_set/code') AS XT(XC)
This basically uses the built-in XQuery to get an "in-memory" table (XT) with a single column (XC), each containing an XML fragment that represents each <code> node inside your <code_set> root node.
Once you have each of these XML fragments, you can use the .value() XQuery operator to "reach in" and grab some pieces of information from it, e.g. it's #id (attribute by the name of id), or the #description attribute on the contained <entry> subelement.
The following query will read the xml field in every row, then shred certain values into a tabular result set.
SELECT
-- get attribute [attribute name] from the parent node
parent.value('./#attribute name','varchar(max)') as ParentAttributeValue,
-- get the text value of the first child node
child.value('./text()', 'varchar(max)') as ChildNodeValueFromFirstChild,
-- get attribute attribute [attribute name] from the first child node
child.value('./#attribute name', 'varchar(max)') as ChildAttributeValueFromFirstChild
FROM
[table name]
CROSS APPLY
-- create a handle named parent that references that <parent node> in each row
[xml field name].nodes('//xpath to parent name') AS ParentName(parent)
CROSS APPLY
-- create a handle named child that references first <child node> in each row
parent.nodes('(xpath from parent/to child)[0]') AS FirstChildNode(child)
GO
Please provide the exact values you want to shred from the XML for a more precise answer.

Creating XML Schema for Bulk Load to SQL Server - Child Element Describes Parent

I have an XML document that I'm working to build a schema for in order to bulk load these documents into a SQL Server table. The XML I'm focusing on looks like this:
<Coverage>
<CoverageCd>BI</CoverageCd>
<CoverageDesc>BI</CoverageDesc>
<Limit>
<FormatCurrencyAmt>
<Amt>30000.00</Amt>
</FormatCurrencyAmt>
<LimitAppliesToCd>PerPerson</LimitAppliesToCd>
</Limit>
<Limit>
<FormatCurrencyAmt>
<Amt>85000.00</Amt>
</FormatCurrencyAmt>
<LimitAppliesToCd>PerAcc</LimitAppliesToCd>
</Limit>
</Coverage>
<Coverage>
<CoverageCd>PD</CoverageCd>
<CoverageDesc>PD</CoverageDesc>
<Limit>
<FormatCurrencyAmt>
<Amt>50000.00</Amt>
</FormatCurrencyAmt>
<LimitAppliesToCd>Coverage</LimitAppliesToCd>
</Limit>
</Coverage>
Inside the Limit element, there's a child LimitAppliesToCd that I need to use to determine where the Amt element's value actually gets stored inside my table. Is this possible to do using the standard XML Bulk Load feature of SQL Server? Normally in XML I'd expect that the element would have an attribute containing the "PerPerson" or "PerAcc" information, but this standard we're using does not call for that.
If anyone has worked with the ACORD standard before, you might know what I'm working with here. Any help is greatly appreciated.
Don't know exactly what you are talking about, but this is a solution to get the information out of your XML.
Assumption: Your XML is already bulk-loaded into a declared variable #xml of type XML:
A CTE will pull the information out of your XML. The final query will then use PIVOT to put your data into the right column.
With a fitting table's structure the actual insert should be simple...
WITH DerivedTable AS
(
SELECT cov.value('CoverageCd[1]','varchar(max)') AS CoverageCd
,cov.value('CoverageDesc[1]','varchar(max)') AS CoverageDesc
,lim.value('(FormatCurrencyAmt/Amt)[1]','decimal(14,4)') AS Amt
,lim.value('LimitAppliesToCd[1]','varchar(max)') AS LimitAppliesToCd
FROM #xml.nodes('/root/Coverage') AS A(cov)
CROSS APPLY cov.nodes('Limit') AS B(lim)
)
SELECT p.*
FROM
(SELECT * FROM DerivedTable) AS tbl
PIVOT
(
MIN(Amt) FOR LimitAppliesToCD IN(PerPerson,PerAcc,Coverage)
) AS p

In Microsoft SQL Server 2008, how can I generate specific XML tags?

I am not familiar with generating XML code from SQL.
After doing some research, I think I need to use a statement like: FOR XML EXPLICIT, FOR XML RAW or FOR XML AUTO, but when I run it on AUTO, the output is a row like this:
<student externalStudentID1="100003" lastName="Smith" externalSiteId="Place"/>
That is close to what I need, but it has to have specific opening and closing tags like:
<student externalStudentID1="100003" externalSiteId="Place"></student>
When I tried using ELEMENTS, RAW, or PATH I ended up with opening and closing tags for all of the elements. EXPLICIT just threw errors and would require rewriting the entire select statement. Can anyone help? Here is my code:
SELECT [externalStudentId1] as StudId, (
SELECT [externalStudentId1],[externalStudentId2],[socialSecurityNumber],sbl.fn_ToSblDate ( [birthDate]) as [birthDate],[lastName],[firstName],[middleName],[informalName],[nameTitle] ,[nameSuffix],[externalCampusId],[externalSiteId]
FROM sbl.[student] as student
WHERE student.externalStudentId1=stud.externalStudentId1
FOR XML Auto
) as SblData
FROM sbl.[student] as stud
WHERE stud.[ExcludeFromSbl] =0
To generate both open and close tag you can add empty inner text node. For example.
SELECT
externalStudentId1 AS '#externalStudentID1',
externalSiteId AS '#externalSiteId',
...
'' AS 'text()' -- This empty string as inner text is added
FROM
sbl.[student]
FOR
XML PATH('student')

Use SQL Server to get all the data from XML nodes named the same

I have an XML file where the nodes that I need the data from are all named the same. I understand how to access the first (or second record) so the following query only gives me the second author (the <a1> tag). How do I get all the authors as a single column ?
DECLARE #MyXML XML
SET #MyXML = '<refworks>
<reference>
<rt>Journal Article</rt>
<sr>Print(0)</sr>
<id>869</id>
<a1>Aabye,Martine G.</a1>
<a1>Hermansen,Thomas Stig</a1>
<a1>Ruhwald,Morten</a1>
<a1>PrayGod,George</a1>
<a1>Faurholt-Jepsen,Daniel</a1>
<a1>Jeremiah,Kidola</a1>
<a1>Faurholt-Jepsen,Maria</a1>
<a1>Range,Nyagosya</a1>
</reference>
</refworks>'
SELECT
author.value('(a1)[2]', 'varchar(MAX)') AS 'Author'
FROM #MyXML.nodes('/refworks/reference') AS ref(author)
Try this :-
SELECT
author.value('./text()[1]', 'varchar(MAX)') AS 'Author'
FROM #MyXML.nodes('//refworks/reference/child::node()') AS ref(author)
where author.value('local-name(.)[1]', 'varchar(100)') ='a1'
child::node() represents an axis specifier which is child and :: is the axis separator.
For understanding child axis which is used to drill down in the node can be found in this MSDN document.
or manipulating xml data in sql server
Updated :-
A much simplier way You were on the right track .Specify the child node in the from clause for filtering the data
SELECT
author.value('(.)[1]', 'varchar(MAX)') AS 'Author'
FROM #MyXML.nodes('/refworks/reference/a1') AS ref(author)

Resources