I am trying to extracts some values and colonnes from xml nodes but it
is working . this is my code
Drop table #TableXML
CREATE TABLE #TableXML(Col1 int primary key, Col2 xml)
Insert into #TableXML values ( 1,
'<CookedUP>
<Evenement Calcul="16">
<Cookie xmlns="http://services.ariel.morneausobeco.com/2007/02" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<AlternateOptionTypeCodes />
<Cash>0</Cash>
<CashInterest>0</CashInterest>
<CashSource>Undefined</CashSource>
<Code>A</Code>
<SmallAmount>0</SmallAmount>
<SmallAmountType>Undefined</SmallAmountType>
</Cookie>
</Evenement>
</CookedUP> '
)
SELECT b.Col1,
x.XmlCol.value('(Cookie/SmallAmount)[1]','VARCHAR(100)') AS SmallAmount,
x.XmlCol.value('(Cookie/cash)[1]','VARCHAR(100)') AS cash
FROM #TableXML b
CROSS APPLY b.Col2.nodes('/CookedUP/Evenement') x(XmlCol)
when i ran this query , i am getting null values.
Your node Cookie has a namespace, so you need to declare that and and use it as part of your path (as it isn't the default namespace). Also, you had cash instead of Cash (xQuery is case sensitive). Thus you get:
WITH XMLNAMESPACES ('http://services.ariel.morneausobeco.com/2007/02' AS ns)
SELECT b.Col1,
x.XmlCol.value('(ns:Cookie/ns:SmallAmount/text())[1]', 'int') AS SmallAmount,
x.XmlCol.value('(ns:Cookie/ns:Cash/text())[1]', 'int') AS Cash
FROM #TableXML b
CROSS APPLY b.Col2.nodes('CookedUP/Evenement') x(XmlCol);
I also changed the datatype to int (this may not be the correct datatype, you might want decimal), as the data is clearly numerical and added /text() to the values (I can't remember the exact reason, but the use of /text() has a performance benefit).
Related
Heads!
In my database, I have a column that contains the following data (examples):
H-01-01-02-01
BLE-01-03-01
H-02-05-1.1-03
The task is to get the second to last element of the array if you would split that using the "-" character. The strings are of different length.
So this would be the result using the above mentioned data:
02
03
1.1
Basically I'm searching for an equivalent of the following ruby-statement for use in a Select-Statement in SQL-Server:
"BLE-01-03-01".split("-")[-2]
Is this possible in any way in SQL Server? After spending some time searching for a solution, I only found ones that work for the last or first element.
Thanks very much for any clues or solutions!
PS: Version of SQL Server is Microsoft SQL Server 2012
As an alternative you can try this:.
--A mockup table with some test data to simulate your issue
DECLARE #mockupTable TABLE (ID INT IDENTITY, YourColumn VARCHAR(50));
INSERT INTO #mockupTable VALUES
('H-01-01-02-01')
,('BLE-01-03-01')
,('H-02-05-1.1-03');
--The query
SELECT CastedToXml.value('/x[sql:column("CountOfFragments")-1][1]','nvarchar(10)') AS TheWantedFragment
FROM #mockupTable t
CROSS APPLY(SELECT CAST('<x>' + REPLACE(t.YourColumn,'-','</x><x>') + '</x>' AS XML))A(CastedToXml)
CROSS APPLY(SELECT CastedToXml.value('count(/x)','int')) B(CountOfFragments);
The idea in short:
The first APPLY will transform the string to a XML like this
<x>H</x>
<x>01</x>
<x>01</x>
<x>02</x>
<x>01</x>
The second APPLY will xquery into this XML to get the count of fragments. As APPLY will add this as a column to the result set, we can use the value using sql:column() to get the wanted fragment by its position.
As I wrote in my comment - using charindex with reverse.
First, create and populate sample table (Please save us this step in your future questions):
DECLARE #T AS TABLE
(
Col Varchar(100)
);
INSERT INTO #T (Col) VALUES
('H-01-01-02-01'),
('BLE-01-03-01'),
('H-02-05-1.1-03');
The query:
SELECT Col,
LEFT(RIGHT(Col, AlmostLastDelimiter-1), AlmostLastDelimiter - LastDelimiter - 1) As SecondToLast
FROM #T
CROSS APPLY (SELECT CharIndex('-', Reverse(Col)) As LastDelimiter) As A
CROSS APPLY (SELECT CharIndex('-', Reverse(Col), LastDelimiter+1) As AlmostLastDelimiter) As B
Results:
Col SecondToLast
H-01-01-02-01 02
BLE-01-03-01 03
H-02-05-1.1-03 1.1
Similar to Zohar's solution, but using CTEs instead of CROSS APPLY to prevent redundancy. I personally find this easier to follow, as you can see what happens in each step. Doesn't make it a better solution though ;)
DECLARE #strings TABLE (data VARCHAR(50));
INSERT INTO #strings VALUES ('H-01-01-02-01') , ('BLE-01-03-01'), ('H-02-05-1.1-03');
WITH rev AS (
SELECT
data,
REVERSE(data) AS reversed
FROM
#strings),
first_hyphen AS (
SELECT
data,
reversed,
CHARINDEX('-', reversed) + 1 AS first_pos
FROM
rev),
second_hyphen AS (
SELECT
data,
reversed,
first_pos,
CHARINDEX('-', reversed, first_pos) AS second_pos
FROM
first_hyphen)
SELECT
data,
REVERSE(SUBSTRING(reversed, first_pos, second_pos - first_pos)) AS result
FROM
second_hyphen;
Results:
data result
H-01-01-02-01 02
BLE-01-03-01 03
H-02-05-1.1-03 1.1
Try this
declare #input NVARCHAR(100)
declare #dlmt NVARCHAR(3);
declare #pos INT = 2
SET #input=REVERSE(N'H-02-05-1.1-03');
SET #dlmt=N'-';
SELECT
CAST(N'<x>'
+ REPLACE(
(SELECT REPLACE(#input,#dlmt,'#DLMT#') AS [*] FOR XML PATH(''))
,N'#DLMT#',N'</x><x>'
) + N'</x>' AS XML).value('/x[sql:variable("#pos")][1]','nvarchar(max)');
I have a table with a xml column.
I require to search for sub string in that xml column for all its node and value. Search should be case insensitive
Structure of XML in each row is different
I used below query to do that,
select * from TableName Where Cast(xmlcolumn as varchar(max) ) like '%searchString%'
this works for short length xml rows, if row length goes huge it cant handle the situation. Only partial of the data was searched.
Suggest me some other ways to achieve.
If this is one time task then I would use exist XML method thus:
DECLARE #Table1 TABLE (
ID INT IDENTITY PRIMARY KEY,
CommentAsXML XML
)
INSERT #Table1 (CommentAsXML)
VALUES (N'<root><item /><item type="Reg">0001</item><item type="Inv">B007</item><item type="Cus">A0001</item><item type="Br">F0001</item></root>')
INSERT #Table1 (CommentAsXML)
VALUES (N'<root><item /><item type="Reg">0005</item><parent><child>B007</child></parent><item type="Br">F0005</item></root>')
INSERT #Table1 (CommentAsXML)
VALUES (N'<root><item /><item type="Reg">0005</item></root>')
-- Following query is searching for B007 within InnerText of all XML elements:
SELECT *
FROM #Table1 t
WHERE t.CommentAsXML.exist('//*[lower-case(text()[1]) eq "b007"]') = 1
Results:
ID CommentAsXML
-- ------------------------------------------------------------------------------------------------------------------------------
1 <root><item type="Reg">0001</item><item type="Inv">B007</item><item type="Cus">A0001</item><item type="Br">F0001</item></root>
2 <root><item type="Reg">0005</item><parent><child>B007</child></parent><item type="Br">F0005</item></root>
Also, if you want to search for some text in XML atrributes' values then following XQuery could be used:
SELECT *
FROM #Table1 t
WHERE t.CommentAsXML.exist('//#*[lower-case(.) eq "reg"]') = 1
Note: in both cases, string constants (ex. "reg") should be with lower cases.
I have the following xml which is being parsed via a MSSQL database using OPENXML with an xquery filter to grab the right rows. Unfortunately, it doesn't seem to grab the appropriate rows, which has me scratching my head.
Using the following XML, I only want to insert the single email address where the Method="Insert", and ignore the remaining two addresses where Method is not present or has another value (which were previously inserted).
<Entities xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" ActiveEntityID="0">
<Entity_Businesses>
<Entity_Business EntityTypeID="5" EntityRoleTypeID="9" Method="Update" Name="test business 76" EIN="" EmployeeCount="75" TotalAssets="750000.00">
<Entity_Emails>
<Entity_Email ID="85" EmailAddress="jones#company.com" />
<Entity_Email ID="0" EmailAddress="smith#company.com" Method="Insert"/>
</Entity_Emails>
<Entity_Contacts>
<Entity_Contact ID="162" EntityTypeID="4" EntityRoleTypeID="9" FName="Joe" MName="k" LName="Smith" SSN="444-44-444" JobTitleID="0" DOB="2007-02-27T00:00:00">
<Entity_Emails>
<Entity_Email ID="86" EmailAddress="individual#test.com"/>
</Entity_Emails>
</Entity_Contact>
</Entity_Contacts>
<Entity_Business>
</Entity_Businesses>
</Entities>
I am using this sql statement:
INSERT into Entity_Email(bsCol, EmailAddress, xmlID, xmlPID)
SELECT DENSE_RANK() OVER( ORDER BY y.parentid ) AS elementid, z.EmailAddress, y.parentid, z.ID
FROM OPENXML( #hDoc, '//Entity_Emails', 1 )
WITH (parentid int '#mp:parentid', id int '#mp:id' ) y
INNER JOIN OPENXML(#hDoc, N'//Entity_Emails/Entity_Email',1) WITH (EmailAddress nvarchar(100), xmlID int '#mp:id', parentid int '#mp:parentid') as z
ON y.id = z.parentid
WHERE #pRI.value('(//Entity_Emails/Entity_Email/#Method)[1]','nvarchar(50)') = 'Insert';
As-is, all three email addresses will be inserted, even though the first and last email node do not have a 'Method" attribute. However if I add 'Method = "DontAdd"' to the other two email addresses, nothing gets inserted.
I have also tried using the predicate:
WHERE #pRI.exist('//Entity_Emails/Entity_Email[#Method="Insert"]') =1;
The result is similar - it inserts all rows, and seems to ignore the fact that two of the Email_Address elements do not have an attribute Method="Insert", regardless of whether the Method attribute exists.
The goal is to filter the xml as it is shredded and only add the email address with the attribute Method="Insert". Right now what I believe I have is actually "If you find Method = 'Insert' in the dataset, insert all rows" vs. "if you find method = 'insert', insert only those rows which have that attribute."
Thank you in advance.
Please note the following answer for those that might be helped in the future. After retrieving the column 'Method' in the z aliased query, I was able to use standard t-sql to filter the results correctly and then insert the correct rows.
INSERT into Entity_Email(bsCol, EmailAddress, xmlID, xmlPID)
SELECT DENSE_RANK() OVER( ORDER BY y.parentid ) AS elementid, z.EmailAddress, z.xmlID, y.parentid
FROM OPENXML( #hDoc, '//Entity_Emails', 1 )
WITH (parentid int '#mp:parentid', id int '#mp:id' ) y
INNER JOIN OPENXML(#hDoc, N'//Entity_Emails/Entity_Email',1) WITH (EmailAddress nvarchar(100), xmlID int '#mp:id', parentid int '#mp:parentid', Method nvarchar(50) '#Method') as z
ON y.id = z.parentid
WHERE z.Method = 'Insert'
In the T-SQL sample code below I am trying to query related pieces of data that are in different nodes in the xml, but I can't figure out how to do that. For example, the LX01_AssignedNumber and the C00302_ProcedureCode values need to be pulled together for the same record. The result should look like this.
CLAIM_SOURCE_ID ITEM_NUMBER HCPCS_LINE_CODE
16202E123456 1 99203
16202E123456 2 96372
Can someone help me?
USE [tempdb];
GO
DECLARE #XML XML =
N'<ns1:X12EnrichedMessage xmlns:ns1="http://schemas.microsoft.com/BizTalk/EDI/EDIFACT/2006/EnrichedMessageXML">
<TransactionSet>
<!-- ProcessLogID=PLG0007182226 ;ProcessLogDetailID=PLG0007182968 ;EnvID=1;RetryCount=1 -->
<ns0:X12_00501_837_P xmlns:ns0="http://schemas.microsoft.com/BizTalk/EDI/X12/2006">
<ns0:TS837_2000A_Loop xmlns:ns0="http://schemas.microsoft.com/BizTalk/EDI/X12/2006">
<ns0:TS837_2000B_Loop xmlns:ns0="http://schemas.microsoft.com/BizTalk/EDI/X12/2006">
<ns0:TS837_2300_Loop xmlns:ns0="http://schemas.microsoft.com/BizTalk/EDI/X12/2006">
<ns0:TS837_2400_Loop>
<ns0:LX_ServiceLineNumber>
<LX01_AssignedNumber>1</LX01_AssignedNumber>
</ns0:LX_ServiceLineNumber>
<ns0:SV1_ProfessionalService>
<ns0:C003_CompositeMedicalProcedureIdentifier>
<C00301_ProductorServiceIDQualifier>HC</C00301_ProductorServiceIDQualifier>
<C00302_ProcedureCode>99203</C00302_ProcedureCode>
<C00303_ProcedureModifier>25</C00303_ProcedureModifier>
<C00307_Description>NO DESCRIPTION</C00307_Description>
</ns0:C003_CompositeMedicalProcedureIdentifier>
<SV102_LineItemChargeAmount>167.82</SV102_LineItemChargeAmount>
<SV103_UnitorBasisforMeasurementCode>UN</SV103_UnitorBasisforMeasurementCode>
<SV104_ServiceUnitCount>1</SV104_ServiceUnitCount>
<ns0:C004_CompositeDiagnosisCodePointer>
<C00401_DiagnosisCodePointer>1</C00401_DiagnosisCodePointer>
</ns0:C004_CompositeDiagnosisCodePointer>
</ns0:SV1_ProfessionalService>
<ns0:DTP_SubLoop_2>
<ns0:DTP_Date_ServiceDate>
<DTP01_DateTimeQualifier>472</DTP01_DateTimeQualifier>
<DTP02_DateTimePeriodFormatQualifier>RD8</DTP02_DateTimePeriodFormatQualifier>
<DTP03_ServiceDate>20160627-20160627</DTP03_ServiceDate>
</ns0:DTP_Date_ServiceDate>
</ns0:DTP_SubLoop_2>
</ns0:TS837_2400_Loop>
<ns0:TS837_2400_Loop>
<ns0:LX_ServiceLineNumber>
<LX01_AssignedNumber>2</LX01_AssignedNumber>
</ns0:LX_ServiceLineNumber>
<ns0:SV1_ProfessionalService>
<ns0:C003_CompositeMedicalProcedureIdentifier>
<C00301_ProductorServiceIDQualifier>HC</C00301_ProductorServiceIDQualifier>
<C00302_ProcedureCode>96372</C00302_ProcedureCode>
<C00307_Description>NO DESCRIPTION</C00307_Description>
</ns0:C003_CompositeMedicalProcedureIdentifier>
<SV102_LineItemChargeAmount>82.56</SV102_LineItemChargeAmount>
<SV103_UnitorBasisforMeasurementCode>UN</SV103_UnitorBasisforMeasurementCode>
<SV104_ServiceUnitCount>2</SV104_ServiceUnitCount>
<ns0:C004_CompositeDiagnosisCodePointer>
<C00401_DiagnosisCodePointer>2</C00401_DiagnosisCodePointer>
</ns0:C004_CompositeDiagnosisCodePointer>
</ns0:SV1_ProfessionalService>
<ns0:DTP_SubLoop_2>
<ns0:DTP_Date_ServiceDate>
<DTP01_DateTimeQualifier>472</DTP01_DateTimeQualifier>
<DTP02_DateTimePeriodFormatQualifier>RD8</DTP02_DateTimePeriodFormatQualifier>
<DTP03_ServiceDate>20160627-20160627</DTP03_ServiceDate>
</ns0:DTP_Date_ServiceDate>
</ns0:DTP_SubLoop_2>
</ns0:TS837_2400_Loop>
</ns0:TS837_2300_Loop>
</ns0:TS837_2000B_Loop>
</ns0:TS837_2000A_Loop>
</ns0:X12_00501_837_P>
</TransactionSet>
</ns1:X12EnrichedMessage>'
IF OBJECT_ID(N'tempdb..#CLAIM_XML', N'U') IS NOT NULL
DROP TABLE #CLAIM_XML;
CREATE TABLE #CLAIM_XML (
CLAIM_SOURCE_ID VARCHAR(20) NOT NULL
,RAW_XML XML NOT NULL
,CLAIM_FORM_TYPE CHAR(1) NOT NULL
,CREATED_DATE DATE NOT NULL
,CONSTRAINT CLAIM_XML_PK PRIMARY KEY (CLAIM_SOURCE_ID)
);
CREATE PRIMARY XML INDEX CLAIM_XML_RAW_XML_IDX
ON #CLAIM_XML (RAW_XML);
INSERT INTO #CLAIM_XML
([CLAIM_SOURCE_ID]
,[RAW_XML]
,[CLAIM_FORM_TYPE]
,[CREATED_DATE])
VALUES('16202E123456'
,#XML
,'H'
,CONVERT(DATE, DATEADD(DAY, -1, GETDATE())));
WITH XMLNAMESPACES ('http://schemas.microsoft.com/BizTalk/EDI/EDIFACT/2006/EnrichedMessageXML' AS ns1
,'http://schemas.microsoft.com/BizTalk/EDI/X12/2006' AS ns0)
SELECT [CX].[CLAIM_SOURCE_ID]
,[ITEM_NUMBER] = LineNumber.ref.value('text()[1]', 'int')
,[HCPCS_LINE_CODE] = [CX].[RAW_XML].value('(/ns1:X12EnrichedMessage/TransactionSet/ns0:X12_00501_837_P/ns0:TS837_2000A_Loop/ns0:TS837_2000B_Loop/ns0:TS837_2300_Loop/ns0:TS837_2400_Loop/ns0:SV1_ProfessionalService/ns0:C003_CompositeMedicalProcedureIdentifier/C00302_ProcedureCode)[1]','varchar(100)')
FROM #CLAIM_XML AS [CX]
CROSS APPLY [CX].[RAW_XML].nodes('/ns1:X12EnrichedMessage/TransactionSet/ns0:X12_00501_837_P/ns0:TS837_2000A_Loop/ns0:TS837_2000B_Loop/ns0:TS837_2300_Loop/ns0:TS837_2400_Loop/ns0:LX_ServiceLineNumber/*') LineNumber(ref)
WHERE [CX].[CLAIM_FORM_TYPE] = 'H'
AND [CX].[CREATED_DATE] = CONVERT(DATE, DATEADD(DAY, -1, GETDATE()));
Use multiple CROSS APPLYs to access the different parts of the XML, like this:
;WITH XMLNAMESPACES ('http://schemas.microsoft.com/BizTalk/EDI/EDIFACT/2006/EnrichedMessageXML' AS ns1
,'http://schemas.microsoft.com/BizTalk/EDI/X12/2006' AS ns0)
SELECT
c.[CLAIM_SOURCE_ID],
sln.c.value('(LX01_AssignedNumber/text())[1]', 'INT') AS [ITEM_NUMBER],
ps.c.value('(ns0:C003_CompositeMedicalProcedureIdentifier/C00302_ProcedureCode/text())[1]', 'INT') AS [HCPCS_LINE_CODE]
FROM #CLAIM_XML c
CROSS APPLY c.[RAW_XML].nodes('/ns1:X12EnrichedMessage/TransactionSet/ns0:X12_00501_837_P/ns0:TS837_2000A_Loop/ns0:TS837_2000B_Loop/ns0:TS837_2300_Loop/ns0:TS837_2400_Loop') l(c)
CROSS APPLY l.c.nodes('ns0:LX_ServiceLineNumber') sln(c)
CROSS APPLY l.c.nodes('ns0:SV1_ProfessionalService') ps(c)
No need for multiple CROSS APPLY with .nodes(). As the values you want to read are single occurance within their tree you can address them directly:
;WITH XMLNAMESPACES ('http://schemas.microsoft.com/BizTalk/EDI/EDIFACT/2006/EnrichedMessageXML' AS ns1
,'http://schemas.microsoft.com/BizTalk/EDI/X12/2006' AS ns0)
SELECT
loop2400.value('(ns0:LX_ServiceLineNumber/LX01_AssignedNumber)[1]', 'INT') AS [ITEM_NUMBER],
loop2400.value('(ns0:SV1_ProfessionalService/ns0:C003_CompositeMedicalProcedureIdentifier/C00302_ProcedureCode)[1]', 'INT') AS [HCPCS_LINE_CODE]
FROM #xml.nodes('/ns1:X12EnrichedMessage/TransactionSet/ns0:X12_00501_837_P/ns0:TS837_2000A_Loop/ns0:TS837_2000B_Loop/ns0:TS837_2300_Loop/ns0:TS837_2400_Loop') A(loop2400)
The lazy approach works too, but - in general - it's good advise to be as specific as possible...
SELECT
loop2400.value('(*//LX01_AssignedNumber)[1]', 'INT') AS [ITEM_NUMBER],
loop2400.value('(*//C00302_ProcedureCode)[1]', 'INT') AS [HCPCS_LINE_CODE]
FROM #xml.nodes('//*:TS837_2400_Loop') A(loop2400)
On SQL Server 2008 R2, I am trying to read XML value as table.
So far, I am here :
DECLARE #XMLValue AS XML;
SET #XMLValue = '<SearchQuery>
<ResortID>1453</ResortID>
<CheckInDate>2011-10-27</CheckInDate>
<CheckOutDate>2011-11-04</CheckOutDate>
<Room>
<NumberOfADT>2</NumberOfADT>
<CHD>
<Age>10</Age>
</CHD>
<CHD>
<Age>12</Age>
</CHD>
</Room>
<Room>
<NumberOfADT>1</NumberOfADT>
</Room>
<Room>
<NumberOfADT>1</NumberOfADT>
<CHD>
<Age>7</Age>
</CHD>
</Room>
</SearchQuery>';
SELECT
Room.value('(NumberOfADT)[1]', 'INT') AS NumberOfADT
FROM #XMLValue.nodes('/SearchQuery/Room') AS SearchQuery(Room);
As you can see, Room node sometimes get CHD child nodes but sometimes don't.
Assume that I am getting this XML value as a Stored Procedure parameter. So, I need to work with the values in order to query my database tables. What would be the best way to read this XML parameter entirely?
EDIT
I think I need to express what I am expecting in return here. The below script code is for the table what I need here :
DECLARE #table AS TABLE(
ResorrtID INT,
CheckInDate DATE,
CheckOutDate DATE,
NumberOfADT INT,
CHDCount INT,
CHDAges NVARCHAR(100)
);
For the XML value I have provide above, the below Insert t-sql is suitable :
INSERT INTO #table VALUES(1453, '2011-10-27', '2011-11-04', 2, 2, '10;12');
INSERT INTO #table VALUES(1453, '2011-10-27', '2011-11-04', 1, 0, NULL);
INSERT INTO #table VALUES(1453, '2011-10-27', '2011-11-04', 1, 1, '7');
CHDCount is for the number of CHD nodes under Room node. Also, how many Room node I have, that many table row I am having here.
As for how it should look, see the below picture :
Actually, this code is for hotel reservation search query. So, I need
to work with these values I got from XML parameter to query my tables
and return available rooms. I am telling this because maybe it helps
you guys to see it through. I am not looking for a complete code for
room reservation system. That would be so selfish.
select S.X.value('ResortID[1]', 'int') as ResortID,
S.X.value('CheckInDate[1]', 'date') as CheckInDate,
S.X.value('CheckOutDate[1]', 'date') as CheckOutDate,
R.X.value('NumberOfADT[1]', 'int') as NumberOfADT,
R.X.value('count(CHD)', 'int') as CHDCount,
stuff((select ';'+C.X.value('.', 'varchar(3)')
from R.X.nodes('CHD/Age') as C(X)
for xml path('')), 1, 1, '') as CHDAges
from #XMLValue.nodes('/SearchQuery') as S(X)
cross apply S.X.nodes('Room') as R(X)
This should get you close:
SELECT ResortID = #xmlvalue.value('(//ResortID)[1]', 'int')
, CheckInDate = #xmlvalue.value('(//CheckInDate)[1]', 'date')
, CheckOutDate = #xmlvalue.value('(//CheckOutDate)[1]', 'date')
, NumberOfAdt = Room.value('(NumberOfADT)[1]', 'INT')
, CHDCount = Room.value('count(./CHD)', 'int')
, CHDAges = Room.query('for $c in ./CHD
return concat(($c/Age)[1], ";")').value('(.)[1]',
'varchar(100)')
FROM #XMLValue.nodes('/SearchQuery/Room') AS SearchQuery ( Room ) ;