【问题标题】:Xquery Get Position()Xquery 获取位置()
【发布时间】:2017-10-09 20:27:52
【问题描述】:

这是我们 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 cmets 的字段....

这是 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'

代码没有错误,但测试字段​​始终为空白。

有什么建议吗?

【问题讨论】:

  • 我不认为位置函数是这样工作的。此外,这显然不会正确返回位置,因为您正在尝试使用 T6 中的路径。 可能对您有用的是带有 row_number() 和外部应用的子查询,而不是交叉应用 T7(ref) 以获得正确的行号,然后排除 t7.ref 为空的那些

标签: sql-server xquery-sql


【解决方案1】:

如果您查找documentation,您会发现,到目前为止,您无法直接返回position() 函数的结果:

在 SQL Server 中,fn:position() 只能用于 上下文相关的谓词。具体来说,只能在里面使用 方括号 ([ ])。

但是,您可以使用一个巧妙的技巧来获得它。即,您可以将元素的位置与已知序列进行比较,然后从该序列返回匹配的值。下面的例子说明了这一点。

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 生成一组有序的整数(我通常保留一个特殊的表,但您可以随时构建一个),匹配条件在定义 x(c) 输出的 XQuery 表达式中指定.

【讨论】:

  • 对于搜索类似内容的人,这是最终查询...
  • SELECT ... T7.ref.value('text()[1]', 'varchar(1000)') AS gTrnTPpOiCDT_Text, xRows1.RN AS gTrnTPpOiC_seqNo, xRows2.RN AS gTrnTPpOiCDT_seqNo .. . 交叉应用 ods.RowNumbers_5 xRows1 交叉应用 T5.ref.nodes('dec...";(./comment[position() = sql:column("xRows1.RN")])') T6(ref) CROSS应用 ods.RowNumbers_1 xRows2 交叉应用 T6.ref.nodes('dec...";(./dutchText[position() = sql:column("xRows2.RN")])') T7(ref) WHERE fi。 file_type = '火车'
  • 不得不将一些零件切割到评论长度限制。但是,将原始查询放在一边,就可以编写了。
【解决方案2】:

我同意 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;

【讨论】:

    【解决方案3】:

    使用Node Order Comparison Operators 来计算 XML 树中前面的 //comment 节点可能更简单,性能更好。

    我没有对大型 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)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-07-15
      • 1970-01-01
      • 2019-08-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-03-12
      相关资源
      最近更新 更多