14

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(),还是例外?

4

1 回答 1

25

是的,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在 an中使用order by。尝试它会给你

Msg 493, Level 16, State 1, Line 19
从 nodes() 方法返回的列 'c' 不能直接使用。它只能用于四种 XML 数据类型方法之一,exist()、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
于 2013-07-20T17:22:34.630 回答