从XML中选择SQL Server中的值

时间:2017-07-26 18:21:29

标签: sql-server xml tsql

我有这个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>

我如何获得

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

1 个答案:

答案 0 :(得分:4)

简单的nodesvalue功能应该足够了:

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

修改

如果你真的需要聚合字符串,你可以使用:

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;

这适用于SQL Server 2017+。对于较低版本,您必须使用不同的方法,如XML或CLR函数。

<强> DBFiddle

编辑2:

使用CROSS APPLY

可以避免@Shnugo避免多次向后导航
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