I have the following code in the select block of my query which picks out rows from a table and outputs them in XML:
select ...
...
,substring(
(
Select RC_1.Master_Code AS [TopographyTDR]
From apex.Histo_Result_Coding as RC_1
Where RC_1.Histo_Report = Histo_Result_Coding.Histo_Report
ORDER BY RC_1.Histo_report
For XML auto
), 1, 1000) [TDRCodes]
...
and this gives an output similar to that shown below:
<RC_1 TopographyTDR="T77100"/><RC_1 TopographyTDR="T77100"/>
<RC_1 TopographyTDR="T01000"/><RC_1 TopographyTDR="T01000"/>
<RC_1 TopographyTDR="EGFR "/> <RC_1 TopographyTDR="GHER2"/>
<RC_1 TopographyTDR="T04020"/><RC_1 TopographyTDR="T04020"/>
<RC_1 TopographyTDR="T77100"/><RC_1 TopographyTDR="T77100"/>
This is the correct data, but I need the tag to be 'TopographyTDR' without the RC_1. i.e. the data should look like:
<TopographyTDR="T77100"/><TopographyTDR="T77100"/>
<TopographyTDR="T01000"/><TopographyTDR="T01000"/>
<TopographyTDR="EGFR "/> <TopographyTDR="GHER2"/>
<TopographyTDR="T04020"/><TopographyTDR="T04020"/>
<TopographyTDR="T77100"/><TopographyTDR="T77100"/>
Is there a simple way to do this? i.e. to avoid having the table name appear in the XML tag text?
Thanks in advance.
You can use for xml path instead of for xml auto and specify tag names explicitly.
Something like:
Select RC_1.Master_Code AS 'TopographyTDR'
From apex.Histo_Result_Coding as RC_1
Where RC_1.Histo_Report = Histo_Result_Coding.Histo_Report
ORDER BY RC_1.Histo_report
for XML path('')
Update:
Looking at your desired output more precisely - it doesn't looks like valid xml.
Despite on missing root node (it could be omitted for simplicity, I suppose), this format has fundamental problem: tag like <TopographyTDR="T77100"/> in fact doesn't has tag name but only has attribute TopographyTDR having value T77100. Are you sure you want such a pseudo-xml data?
Your desired format is not allowed. An XML node must have a tag name and a content or attributes. And you'll need a root...
You must use PATH instead of AUTO. Look at this:
select top 3 name
from sys.objects
for xml path(''),ROOT('root');
select top 3 name AS [#attrib]
from sys.objects
for xml path('item'),ROOT('root')
Related
I'm trying to construct a soap message, and I was able to construct the entire message using a single select. Except the problem is, on only a few occasions the same node name is repeated twice.
So for example the required output result should be like so, with two separate id root nodes:
<SoapDocument>
<recordTarget>
<patientRole>
<id root="1.2.3.4" extension="1234567" />
<id root="1.2.3.5.6" extension="0123456789" />
</patientRole>
</recordTarget>
</SoapDocument>
I tried to use my sparse knowledge of xpath to construct the node names like so:
select
'1.2.3.4' AS 'recordTarget/patientRole/id[1]/#root',
'1234567' AS 'recordTarget/patientRole/id[1]/#extension',
'1.2.3.5.6' AS 'recordTarget/patientRole/id[2]/#root',
'0123456789' AS 'recordTarget/patientRole/id[2]/#extension'
FOR XML PATH('SoapDocument'),TYPE
Apparently xpath naming can't be applied to column names id[1] and id[2] like that? Am I missing something here or should the notation be different? What would be the easiest way to constuct the desired result?
From your question I assume, this is not tabular data, but fixed values and you are creating a medical document, assumably a CDA.
Try this:
SELECT
(
SELECT
'1.2.3.4' AS 'id/#root',
'1234567' AS 'id/#extension',
'',
'1.2.3.5.6' AS 'id/#root',
'0123456789' AS 'id/#extension'
FOR XML PATH('patientRole'),TYPE
) AS [SoapDocument/recordTarget]
FOR XML PATH('')
The result:
<SoapDocument>
<recordTarget>
<patientRole>
<id root="1.2.3.4" extension="1234567" />
<id root="1.2.3.5.6" extension="0123456789" />
</patientRole>
</recordTarget>
</SoapDocument>
Some explanation: The empty element in the middle allows you to place two elements with the same name in one query. There are various approaches how you get this into your surrounding tags. This is just one possibility.
UPDATE
I'd like to point to BdR's own answer! Great finding and worth an up-vote!
A little more elaboration on the answer from Shnugo, as it got me trying out some things using an "empty column".
If you do not give the emtpy column a name, it will reset to the XML root node. So the following columns will start from the XML root of the selection you are in at that point. However, if you explicitly name the empty separator column, then the following columns will continue in the hierarchy as set by that column name.
So the selection below will also result in the desired result. It's subtly different, but in my case it allows me to avoid using subselections.
select
'1.2.3.4' AS 'recordTarget/patientRole/id/#root',
'1234567' AS 'recordTarget/patientRole/id/#extension',
'' AS 'recordTarget/patientRole',
'1.2.3.5.6' AS 'recordTarget/patientRole/id/#root',
'0123456789' AS 'recordTarget/patientRole/id/#extension'
FOR XML PATH('SoapDocument'),TYPE
This should do the job:
WITH CTE AS (
SELECT *
FROM (VALUES('1.2.3.4','1234567'),
('1.2.3.5.6','0123456789')) V ([root], [extension]))
SELECT (SELECT (SELECT (SELECT [root] AS [#root],
[extension] AS [#extension]
FROM CTE
FOR XML PATH('id'), TYPE)
FOR XML PATH('patientRole'), TYPE)
FOR XML PATH ('recordTarget'), TYPE)
FOR XML PATH ('SoapDocument');
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.
I have this XML:
i want to get the value on Property name = "ParticipTypeName" i am using something like that:
;WITH XMLNAMESPACES(DEFAULT 'http://xml.common.asset.aoma.sonymusic.com/ProductMetadata.xsd')
SELECT
x.u.value('(/BusinessUnitProperties/Property[#name = "ParticipTypeName"])[1]', 'varchar(100)') as ParticipTypeName
from
#XML.nodes('/ProductMetadata/Tracks/Track/Participants/Participant') x(u)
it doesn't work.
How I should get the value in this property?
Try this:
SELECT x.u.value('(//*:Property[#*:name="ParticipTypeName"])[1]','nvarchar(max)')
The // will search for any element <Property>. The XQuery-filter will choose the one with the name you are looking for. The *: will allow you to ignore the namespace.
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')
I use a nested query to concatenate row data for an aggregate. The syntax I use within the nested query is
for XML PATH ('')
Can someone explain what is supposed to go between the quotes above? I did some tests and it looks like it just encloses my row data in start and ending HTML like tags.
I'm not 100% sure what you mean, but if your query is similar to the following then that might help you:
SELECT R.RegionID AS [#RID],
R.Enabled AS [#Enabled],
(
SELECT ST.TypeID AS [#TID],
QT.[Name] AS [#QTName],
FROM Type ST
INNER JOIN QuarryType QT ON ST.QuarryTypeID = QT.QuarryTypeID
WHERE R.RegionID = ST.RegionID
FOR XML PATH ('QuarryType'), TYPE
)
FROM Region R
FOR XML PATH ('Region'), ELEMENTS, ROOT('root')
As you can see the text in each FOR XML PATH ('') block is nothing special, not related to the data anyway. It is used for element names in your XML output like this:
<root>
<Region RID="123" Enabled="true">
<QuarryType TID="4" QTName="Quarry 1"/>
<QuarryType TID="7" QTName="Quarry 2"/>
<QuarryType TID="9" QTName="Quarry 5"/>
</Region>
</root>
If you need more help, just ask!
The empty string ('') is a special case. Your observation is correct in that whatever you put there will surround your row with open and close XML tags of whatever you put in there. For instance, if you say "for xml path ('a')", it will surround your results with <a> </a>.