`nodes()`方法是否保持文档顺序?

时间:2013-07-19 13:59:16

标签: sql-server xml tsql

nodes()数据类型的xml方法是否按文档顺序返回节点?

例如,如果有以下数据:

declare @xml xml
set @xml = '<Fruits><Apple /><Banana /><Orange /><Pear /></Fruits>'

被查询为

select T.c.query('.')
from @xml.nodes('/Fruits/*') T(c)

元素会按文档顺序返回吗?如果省略select子句,则order by返回的行的顺序是未定义的。是select ... from ... .nodes()的情况,还是例外?

在某些情况下,是否有可能在以下查询的输出中获得非空行集:

declare @xml xml
set @xml = '<Data><Element OrderNo="1" /><Element OrderNo="2" />'
  + '<Element OrderNo="3" /><Element OrderNo="4" />'
  + '<Element OrderNo="5" /></Data>'

select * from (
    select T.c.value('.', 'int') OrderNo1, 
      row_number() over (order by @@spid) OrderNo2
    from @xml.nodes('/Data/Element/@OrderNo') T(c)) sq
where OrderNo1 != OrderNo2

1 个答案:

答案 0 :(得分:20)

是的,nodes()按文档顺序生成一行。查询计划中使用的运算符是Table Valued Function XML Reader

  

表值函数XML Reader输入XML BLOB作为参数和   生成一个表示XML文档顺序的XML节点的行集。其他   输入参数可以限制返回到XML子集的XML节点   文档。

但是没有order by的查询有一个未定义的顺序,所以没有保证。

解决这个问题的一种方法是使用id子句中由表值函数生成的row_number() over(),并按顺序使用生成的数字。

select X.q
from
  (
  select T.c.query('.') as q,
         row_number() over(order by T.c) as rn
  from @xml.nodes('/Fruits/*') T(c)
  ) as X
order by X.rn

无法直接在T.c中使用order by。试着这会给你

  

Msg 493,Level 16,State 1,Line 19   
从nodes()方法返回的列'c'不能直接使用。它只能与四种XML数据类型方法之一,exists(),nodes(),query()和value()一起使用,或者在IS NULL和IS NOT NULL检查中使用。

错误没有提到它应该与row_number一起使用,但确实如此,这很可能是可能修复的错误,因此上面的代码将失败。但直到SQL Server 2012它才能正常工作。

在不依赖于row_number的未记录使用的情况下获得保证订单的方法是使用数字表,您可以按位置提取节点。

select T.c.query('.') as q
from Numbers as N
  cross apply @xml.nodes('/Fruits/*[sql:column("N.Number")]') as T(c)
where N.Number between 1 and @xml.value('count(/Fruits/*)', 'int')
order by N.Number