1

I have this XML:

 <SearchResponse>
    <Data>
        <Information>
            <Code>Code 1</Code>
            <Options>
                <Option>
                    <TID>1</TID>
                    <Rooms>
                        <ReturnRoom>
                            <RoomId>1</RoomId>
                            <Description>Single</Description>
                        </ReturnRoom>
                        <ReturnRoom>
                            <RoomId>2</RoomId>
                            <Description>Standard</Description>
                        </ReturnRoom>
                    </Rooms>
                </Option>
                <Option>
                    <TID>2</TID>
                    <Rooms>
                        <ReturnRoom>
                            <RoomId>1</RoomId>
                            <Description>Single</Description>
                        </ReturnRoom>
                    </Rooms>
                </Option>
            </Options>
        </Information>      
    </Data>
</SearchResponse>

How I can get

Code      Name     TID  RoomId    Description 
---------------------------------------------------
Code 1    Hotel 1   1  1;2     Single;Standard
Code 1    Hotel 1   2   1      Single

1 Answer 1

4

Simple nodes and value functions should be sufficient:

DECLARE @xml XML = N'<SearchResponse>
    <Data>
        <Information>
            <Code>Code 1</Code>
            <Options>
                <Option>
                    <TID>1</TID>
                    <Rooms>
                        <ReturnRoom>
                            <RoomId>1</RoomId>
                            <Description>Single</Description>
                        </ReturnRoom>
                        <ReturnRoom>
                            <RoomId>2</RoomId>
                            <Description>Standard</Description>
                        </ReturnRoom>
                    </Rooms>
                </Option>
                <Option>
                    <TID>2</TID>
                    <Rooms>
                        <ReturnRoom>
                            <RoomId>1</RoomId>
                            <Description>Single</Description>
                        </ReturnRoom>
                    </Rooms>
                </Option>
            </Options>
        </Information>      
    </Data>
</SearchResponse>';


SELECT  b.value('(../../../../Code/text())[1]', 'NVARCHAR(MAX)') AS Code
       ,b.value('(../../TID/text())[1]', 'NVARCHAR(MAX)') AS TID
       ,b.value('(./RoomId/text())[1]', 'NVARCHAR(MAX)') AS RoomId
       ,b.value('(./Description/text())[1]', 'NVARCHAR(MAX)') AS Description
FROM @xml.nodes('/SearchResponse/Data/Information/Options/Option/Rooms/ReturnRoom') AS a(b);

Rextester demo


EDIT:

If you really need to aggregate string you could use:

WITH cte AS (
  SELECT  b.value('(../../../../Code/text())[1]', 'NVARCHAR(MAX)') AS Code
       ,b.value('(../../TID/text())[1]', 'NVARCHAR(MAX)') AS TID
       ,b.value('(./RoomId/text())[1]', 'NVARCHAR(MAX)') AS RoomId
       ,b.value('(./Description/text())[1]', 'NVARCHAR(MAX)') AS Description
  FROM @xml.nodes('/SearchResponse/Data/Information/Options/Option/Rooms/ReturnRoom') AS a(b)
)
SELECT Code, TID,
      STRING_AGG(RoomId, ';') AS RoomId,
      STRING_AGG(Description, ';') AS Description
FROM cte
GROUP BY Code, TID;

This will work for SQL Server 2017+. With lower version you have to use different method like XML or CLR function.

DBFiddle


EDIT 2:

As @Shnugo avoid multiple backward navigation could be avoided by using CROSS APPLY:

WITH cte AS (
  SELECT  b.value('(../../Code/text())[1]', 'NVARCHAR(MAX)') AS Code
       ,b.value('(TID/text())[1]', 'NVARCHAR(MAX)') AS TID
       ,d.value('(RoomId/text())[1]', 'NVARCHAR(MAX)') AS RoomId
       ,d.value('(Description/text())[1]', 'NVARCHAR(MAX)') AS Description
  FROM @xml.nodes('/SearchResponse/Data/Information/Options/Option') AS a(b)
  CROSS APPLY a.b.nodes('Rooms/ReturnRoom') AS c(d)
)
SELECT Code, TID, STRING_AGG (RoomId, ';'), STRING_AGG(Description, ';')
FROM cte
GROUP BY Code, TID;

DBFiddle 2

Sign up to request clarification or add additional context in comments.

1 Comment

Good answer, +1 from my side, but I'd rather use a call to .nodes() down to <Option> and an APPLY to .nodes() down to <ReturnRooms>. Backward navigation (like ../../../../Code) is slow and not very intuitive...

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.