迭代XML" cousins"与SQL Server

时间:2016-03-12 12:30:29

标签: sql-server xml xpath

我将以下XML文档存储在具有XML类型的TSQL变量中:

<root>
  <parent>
    <child>Alice</child>
    <child>Bob</child>
    <child>Carol</child>
  </parent>
  <house>
    <room><id>1</id></room>
    <room><id>2</id></room>
    <room><id>3</id></room>
  </house>
</root>

我想迭代&#34;堂兄&#34;节点(即父节点为兄弟节点的节点)并在表中插入每行迭代一行,每个表兄插入一列。所以结果会是这样的:

Child | Room
------------
Alice | 1
Bob   | 2
Carol | 3

(我知道有一个与孩子一样多的房间。)

我觉得这是一项简单的任务,但似乎无法找到方法。我是SQL Server和XPath的初学者,可能缺乏查找文档的术语。

我到目前为止尝试的是迭代,比如child元素,并尝试使用room从那里读取匹配的ROW_NUMBER元素来挑选房间我想要:

INSERT INTO children (child, room)
SELECT 
  child = T.Item.value('(../parent/child/text())[' + (ROW_NUMBER() OVER(ORDER BY T.Item)) + ']', 'VARCHAR(10)'),
  room = T.Item.value('(id/text())[1]', 'CHAR(1)')
FROM   
  @XML.nodes('root/house/room') AS T(Item)

但是SQL服务器抱怨value()只接受字符串文字作为第一个参数(那是什么限制?)。

我知道如何才能做到这一点吗?

2 个答案:

答案 0 :(得分:5)

不确定这是最佳还是最短路,但它会产生您需要的输出:

DECLARE @x XML='
<root>
  <parent>
    <child>Alice</child>
    <child>Bob</child>
    <child>Carol</child>
  </parent>
  <house>
    <room><id>1</id></room>
    <room><id>2</id></room>
    <room><id>3</id></room>
  </house>
</root>';

;WITH childs AS (
    SELECT
        n.e.value('.','NVARCHAR(128)') AS child,
        id=ROW_NUMBER() OVER (ORDER BY (SELECT NULL))
    FROM
        @x.nodes('/root/parent/child') AS n(e)
),
room_ids AS (
    SELECT
        n.e.value('.','NVARCHAR(128)') AS room_id,
        id=ROW_NUMBER() OVER (ORDER BY (SELECT NULL))
    FROM
        @x.nodes('/root/house/room/id') AS n(e)
)
SELECT
    c.child,
    r.room_id
FROM
    childs AS c
    INNER JOIN room_ids AS r ON
        r.id=c.id
ORDER BY
    c.id;

答案 1 :(得分:3)

作为纯XPath查询,您可以这样做:

SELECT The.Room.value('id[1]','varchar(max)'),The.Room.value('let $r:=. return (../../parent/child[position()=$r]/text())[1]','varchar(max)')
FROM @YourXML.nodes('/root/house/room') AS The(Room)

但是 - 说实话 - 我更喜欢TT。的解决方案。该解决方案依赖于房间从1到n编号而没有间隙。即使是未分类的房间号码,TT。的解决方案也能正常工作......