这是我们的xml文件的一部分。
<point distanceTotal="162" seqNo="189">
<lineSection id="395" track="1" direction="1">
<outInfos>
<comment commentTypeId="4" priority="1"oneLiner="BOT">
<layerVPK seasonValue="S0"/>
<vectors>
<vector dateFrom="2016-12-11"/>
</vectors>
<frenchText>1x3 MH</frenchText>
</comment>
<comment commentTypeId="4" priority="1" oneLiner="bot">
<layerVPK seasonValue="S0"/>
<frenchText>Réception voie occupée</frenchText>
<dutchText>Test</dutchText>
</comment>
</outInfos>
</point>
我们将其上传到SqlServer列,并使用XQuery获取值。 但是,我找不到一种方法来获得position()编码,并且基本上不能使用T-SQL ROW_NUMBER或密集等级,因为并不总是存在所有数据。 例如,dutchText仅存在于第二个注释中,并且没有标识2个注释的字段....
这是SQL代码
SELECT fi.file_uid,
fi.file_date,
T1.ref.value('@id', 'varchar(100)') AS gTV_id,
T2.ref.value('@id', 'varchar(100)') AS gTrn_id,
T4.ref.value('@seqNo', 'varchar(100)') AS gTrnTPp_seqNo,
T7.ref.value('text()[1]', 'varchar(1000)') AS gTrnTPpOiCDT_Text,
T6.ref.query('/globalTrainVariant/trains/globalTrainVariant/train/timetablePoints/point/outInfos/comment[position()]') AS Test
FROM ods.filesin fi
CROSS APPLY fi.file_xml.nodes('declare namespace cern="http://...";
(/cern:trains/globalTrainVariant)') T1(ref)
CROSS APPLY T1.ref.nodes('declare namespace cern="http://...";
(train)') T2(ref)
CROSS APPLY T2.ref.nodes('declare namespace cern="http://...";
(timetablePoints)') T3(ref)
CROSS APPLY T3.ref.nodes('declare namespace cern="http://...";
(point)') T4(ref)
CROSS APPLY T4.ref.nodes('declare namespace cern="http://...";
(outInfos)') T5(ref)
CROSS APPLY T5.ref.nodes('declare namespace cern="http://...";
(comment)') T6(ref)
CROSS APPLY T6.ref.nodes('declare namespace cern="http://...";
(dutchText)') T7(ref)
WHERE fi.file_type = 'trains'
代码没有错误,但Test字段始终为空白。
有什么建议吗?
答案 0 :(得分:0)
如果您要查找documentation,您会看到,截至目前,您无法直接返回position()
函数的结果:
在SQL Server中, fn:position()只能在a的上下文中使用 依赖于上下文的谓词。具体来说,它只能在里面使用 括号([])。
然而,你可以采用一种巧妙的技巧来获得它。也就是说,您可以将元素的位置与已知序列进行比较,然后从该序列返回匹配的值。下面的例子说明了这一点。
declare @x xml = N'<point distanceTotal="162" seqNo="189">
<outInfos>
<comment commentTypeId="4" priority="1" oneLiner="BOT">
<layerVPK seasonValue="S0" />
<vectors>
<vector dateFrom="2016-12-11" />
</vectors>
<frenchText>1x3 MH</frenchText>
</comment>
<comment commentTypeId="4" priority="1" oneLiner="bot">
<layerVPK seasonValue="S0" />
<frenchText>Réception voie occupée</frenchText>
<dutchText>Test</dutchText>
</comment>
</outInfos>
</point>';
with cte as (
select top (1000) row_number() over(order by ac.object_id) as [RN]
from sys.all_columns ac
)
select t.c.query('.') as [OutInfos], sq.RN as [TextPosition], x.c.query('.') as [DutchComment]
from @x.nodes('/point/outInfos') t(c)
cross join cte sq
cross apply t.c.nodes('./comment[position() = sql:column("sq.RN")]/dutchText') x(c);
在其中,CTE生成一个有序的整数集(我通常会保留一个特殊的表,但你可以随时构造一个),并在定义{{1}的XQuery表达式中指定匹配条件输出。
答案 1 :(得分:0)
我同意Roger的观点,即position()函数不能直接调用,应该在[]内。但是,有一个解决方案不需要任何其他表,并通过使用递归支持任意数量的行:
declare @Xml xml = N'<?xml version="1.0" encoding="utf-16"?>
<root>
<n>1</n>
<n>10</n>
<n>5</n>
<n>3</n>
<n>11</n>
</root>';
with cte as
(
select t.c.value(N'n[1]', N'int') n, 1 RowNum
from @Xml.nodes(N'root[1]') t(c)
where t.c.exist(N'n[1]') = 1
union all
select t.c.value(N'n[position() = sql:column("cte.RowNum") + 1][1]', N'int') n, cte.RowNum + 1
from @Xml.nodes(N'root[1]') t(c)
cross join cte
where t.c.exist(N'n[position() = sql:column("cte.RowNum") + 1]') = 1
)
select *
from cte;
答案 2 :(得分:0)
使用Node Order Comparison Operators来计算XML树中的前面//注释节点可能更简单,性能更好。
我没有对大量的XML文档进行测试,但它确实减少了I / O密集度,并且在我的人工测试中占用的CPU更少。
declare @x xml = N'<point distanceTotal="162" seqNo="189">
<outInfos>
<comment commentTypeId="4" priority="1" oneLiner="BOT">
<layerVPK seasonValue="S0" />
<vectors>
<vector dateFrom="2016-12-11" />
</vectors>
<frenchText>1x3 MH</frenchText>
</comment>
<comment commentTypeId="4" priority="1" oneLiner="bot">
<layerVPK seasonValue="S0" />
<frenchText>Réception voie occupée</frenchText>
<dutchText>Test</dutchText>
</comment>
</outInfos>
</point>';
select
[OutInfos] = t.c.query('../..'),
[TextPosition] = t.c.value('let $dutchText := . return count(../../comment[. << $dutchText])', 'int'),
[DutchComment] = t.c.query('.')
from @x.nodes('/point/outInfos/comment/dutchText') t(c)