(这更多的是一个文档问题,而不是行为问题。它已按照那里的建议从Stack overflow迁移过来。)
在研究另一个需要按原始元素顺序提取 XML 节点的问题的答案时,我遇到了几个答案(此处、此处和此处),它们使用了形式为的表达式ROW_NUMBER() OVER (ORDER BY xml.node)
,并断言或暗示分配的行号值将按 XML 文档顺序分配。
但是,我找不到任何定义 行为的地方ORDER BY xml.node
。尽管子句中似乎允许这样做OVER()
,但文档并未具体提及 XML 节点。
例如,给定:
DECLARE @xml XML = '<root>
<node>One</node>
<node>Two</node>
<node>Three</node>
<node>Four</node>
</root>'
SELECT
ROW_NUMBER() OVER(ORDER BY xml.node) AS rn,
xml.node.value('./text()[1]', 'varchar(255)') AS value
FROM @xml.nodes('*/node') xml(node)
ORDER BY
ROW_NUMBER() OVER(ORDER BY xml.node)
返回结果如下:
rn | value
----------
1 | One
2 | Two
3 | Three
4 | Four
问题:文档中是否有任何地方保证这些结果?这是否被接受为有保证但未记录的行为?或者这是否是另一种情况,ORDER BY (SELECT NULL)
对于看似预先排序的小型源数据集似乎有效,但最终在扩大规模时可能会失败?我之所以问这个问题,是因为我宁愿不推荐使用其行为和可靠性不受文档支持的技术。
有趣的是,尽管 XML 节点可以在 windowed 中使用ORDER BY
,但在普通的 中却不允许SELECT ... ORDER BY
。在普通的 select order-by 子句中使用时,ORDER BY xml.node
会产生以下错误:
消息 493 级别 16 状态 1 第 7 行
从 nodes() 方法返回的列“node”不能直接使用。它只能与四种 XML 数据类型方法(exist()、nodes()、query() 和 value())之一一起使用,或者在 IS NULL 和 IS NOT NULL 检查中使用。
上述错误消息没有列出窗口函数OVER(ORDER BY ...)
作为允许的用途。
不,没有记录,因此无法保证。
实际上,它可能如我在Stack Overflow 答案(如下所示)中所述得到保证,但这并不能满足您对官方文档的渴望。
您可以通过打开文档问题来要求他们记录此事。
我个人会使用它,因为证据对我来说是可以接受的,但如果您也这样做,我不会赔偿您的损失。
我的 Stack Overflow 答案
无法在执行计划中明确看到它,但
id
该方法返回的列nodes()
是varbinary(900)
OrdPath,它确实封装了原始 xml 文档 order。Mikael Eriksson 针对相关问题该方法是否保持文档顺序?提供的解决方案依赖于OrdPath来提供一个必要的子句,以确定如何为 分配标识值。
nodes()
ORDER BY
INSERT
稍微更紧凑的用法如下:
db<>小提琴
目前还没有记录以这种方式使用OrdPath,但该技术在原则上是合理的:
ROW_NUMBER
按OrdPath * 排序的序列值。ORDER BY
子句使用行号序列。ORDER BY
。需要明确的是,即使采用并行性,这也适用。正如 Mikael 所说,可疑的方面是使用,
id
因为ROW_NUMBER
没有id
记录为OrdPath。* 计划中未显示顺序,但使用 TF 8607 的优化器输出包含: