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

i-o*_*one 13 xml t-sql sql-server

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

例如,如果有以下数据:

declare @xml xml
set @xml = '<Fruits><Apple /><Banana /><Orange /><Pear /></Fruits>'
Run Code Online (Sandbox Code Playgroud)

被查询为

select T.c.query('.')
from @xml.nodes('/Fruits/*') T(c)
Run Code Online (Sandbox Code Playgroud)

元素将按文档顺序返回吗?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
Run Code Online (Sandbox Code Playgroud)

Mik*_*son 20

是,nodes()按文档顺序生成行集.在查询计划中使用的运算符是表值函数XML读取器.

表值函数XML Reader将XML BLOB作为参数输入,并生成以XML文档顺序表示XML节点的行集.其他输入参数可能会限制返回到XML文档子集的XML节点.

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

解决这个问题的一种方法是使用id由表值函数in 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
Run Code Online (Sandbox Code Playgroud)

这是不可能使用T.c一个在order by直接.尝试这会给你

消息493,级别16,状态1,行19
从nodes()方法返回的列'c'不能直接使用.它只能与四个XML数据类型的方法之一使用的,存在(),节点(),查询()和()的值,或在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
Run Code Online (Sandbox Code Playgroud)

  • 虽然我赞成这篇文章(因为它包含了我在这个主题上看到的最好的信息集合),但这是微软SQL实现中的一个明确漏洞.Oracle,DB2和PostgreSQL(至少)在XMLTables中有FOR ORDINALITY列.我发现使用T-SQL(非ANSI)XML扩展更容易一些事情; 使用ANSI风格的SQL/XML更容易.大多数情况下,它是洗涤.但这是一个明显缺失的功能,没有干净的选择(他说,希望MS正在倾听). (4认同)