eri*_*len 18 xml sql sql-server xquery
如何在XML文档中找到节点的顺序?
我所拥有的是这样的文件:
<value code="1">
<value code="11">
<value code="111"/>
</value>
<value code="12">
<value code="121">
<value code="1211"/>
<value code="1212"/>
</value>
</value>
</value>
Run Code Online (Sandbox Code Playgroud)
而我正试图将这个东西放到一个定义为的表中
CREATE TABLE values(
code int,
parent_code int,
ord int
)
Run Code Online (Sandbox Code Playgroud)
保留XML文档中值的顺序(它们不能按代码排序).我希望能够说出来
SELECT code
FROM values
WHERE parent_code = 121
ORDER BY ord
Run Code Online (Sandbox Code Playgroud)
结果应该是确定的
code
1211
1212
Run Code Online (Sandbox Code Playgroud)
我试过了
SELECT
value.value('@code', 'varchar(20)') code,
value.value('../@code', 'varchar(20)') parent,
value.value('position()', 'int')
FROM @xml.nodes('/root//value') n(value)
ORDER BY code desc
Run Code Online (Sandbox Code Playgroud)
但它不接受该position()函数(' position()'只能在谓词或XPath选择器中使用).
我想这可能是某种方式,但如何?
Mic*_*Liu 34
您可以position()通过计算每个节点前面的兄弟节点的数量来模拟该函数:
SELECT
code = value.value('@code', 'int'),
parent_code = value.value('../@code', 'int'),
ord = value.value('for $i in . return count(../*[. << $i]) + 1', 'int')
FROM @Xml.nodes('//value') AS T(value)
Run Code Online (Sandbox Code Playgroud)
这是结果集:
code parent_code ord
---- ----------- ---
1 NULL 1
11 1 1
111 11 1
12 1 2
121 12 1
1211 121 1
1212 121 2
Run Code Online (Sandbox Code Playgroud)
这个怎么运作:
for $i in .子句定义了一个名为$i包含当前节点(.)的变量.这基本上是一个解决XQuery缺乏类似XSLT current()功能的黑客.../*表达式选择当前节点的所有兄弟节点(父节点的子节点).[. << $i]谓词过滤兄弟姐妹的那些先于列表(<<)当前节点($i).count()先前的兄弟姐妹的数量,然后加1来获得位置.这样,第一个节点(没有前面的兄弟节点)被分配了1的位置.您可以x.nodes()像这样获取函数返回的xml的位置:
row_number() over (order by (select 0))
Run Code Online (Sandbox Code Playgroud)
例如:
DECLARE @x XML
SET @x = '<a><b><c>abc1</c><c>def1</c></b><b><c>abc2</c><c>def2</c></b></a>'
SELECT
b.query('.'),
row_number() over (partition by 0 order by (select 0))
FROM
@x.nodes('/a/b') x(b)
Run Code Online (Sandbox Code Playgroud)
SQL Server row_number()实际上接受一个xml-nodes列来排序.结合递归CTE,您可以这样做:
declare @Xml xml =
'<value code="1">
<value code="11">
<value code="111"/>
</value>
<value code="12">
<value code="121">
<value code="1211"/>
<value code="1212"/>
</value>
</value>
</value>'
;with recur as (
select
ordr = row_number() over(order by x.ml),
parent_code = cast('' as varchar(255)),
code = x.ml.value('@code', 'varchar(255)'),
children = x.ml.query('./value')
from @Xml.nodes('value') x(ml)
union all
select
ordr = row_number() over(order by x.ml),
parent_code = recur.code,
code = x.ml.value('@code', 'varchar(255)'),
children = x.ml.query('./value')
from recur
cross apply recur.children.nodes('value') x(ml)
)
select *
from recur
where parent_code = '121'
order by ordr
Run Code Online (Sandbox Code Playgroud)
顺便说一句,你可以这样做,它会做你期望的事情:
select x.ml.query('.')
from @Xml.nodes('value/value')x(ml)
order by row_number() over (order by x.ml)
Run Code Online (Sandbox Code Playgroud)
为什么,如果这有效,你不能order by x.ml直接没有row_number() over超越我.
| 归档时间: |
|
| 查看次数: |
13992 次 |
| 最近记录: |