【问题标题】:Reading XML repeated tags in sql server在sql server中读取XML重复标签
【发布时间】:2015-07-01 00:16:55
【问题描述】:
 Declare @MainXml XML = 
 '<?xml version="1.0" encoding="utf-8"?>
 <result>
 <cash number="10">
 <account amt="11.00" status="Closed"/>
 <account amt="12.00" status="Closed"/>                       
 </cash>        
 <cash number="20">
 <account amt="21.00" status="Closed"/>
 <account amt="22.00" status="Closed"/>                       
 </cash>        
 </result>'

我正在使用以下查询读取数据

Declare @Innerxml xml; 
SELECT @Innerxml = T.c.query('<result>{/result/cash}</result>')
FROM   @MainXml.nodes('result') T(c)

SELECT  
Result.Claim.value('(./@number)[1]','varchar(max)') as C1,
Result.Claim.value('(./@amt)[1]','varchar(max)') as C2,
Result.Claim.value('(./@status)[1]','varchar(max)') as C3   
From @Innerxml.nodes('/result/cash/account') Result(Claim)

我想读取 xml 并存储在 DB 中,如下所示。

C1   C2     C3
----------------
10   11.00  Closed
10   12.00  Closed
20   21.00  Closed
20   22.00  Closed

但我的查询在 C1 列中只返回 NULL 请在这里帮助我。提前致谢

【问题讨论】:

    标签: sql-server xml sql-server-2008 xml-parsing sqlxml


    【解决方案1】:

    您不应在 SQL Server 的 XML 查询中使用父轴。创建的查询计划将是 O(n2)。对于 XML 中的每个节点,都会检查 XML 中的所有节点。

    首先切碎result/cash,然后在交叉应用中切碎account

    select C.X.value('@number', 'varchar(max)') as C1,
           A.X.value('@amt', 'varchar(max)') as C2,
           A.X.value('@status', 'varchar(max)') as C3
    from @MainXml.nodes('result/cash') as C(X)
      cross apply C.X.nodes('account') as A(X)
    

    我看不出创建第二个 XML 变量的意义。直接使用@MainXML

    【讨论】:

    • 虽然这听起来合乎逻辑,但我不确定这是否总是正确的。我认为我已经看到使用.. 的查询有时比使用多个这样的应用的查询执行得更好,但我目前没有任何确切的例子。也就是说,测试它会很有趣
    • 我也不同意那个计划是O(n^2),它应该是线性的,因为每个节点只有一个父节点
    • 谢谢,很好的答案!正如我所说,最好像你在这里所做的那样粉碎 xml 是完全有道理的,这始终是我的第一次尝试,我只是记得我已经看到了父节点工作得更好的情况,但同样,现在没有例子。
    • @RomanPekar 也许你有一个 XML 索引?如果您这样做,计划会有所不同。
    【解决方案2】:

    @number&lt;cash&gt; 的属性,但您的上下文节点是&lt;account&gt;。在访问属性之前,您需要在 XML 树上上一层以到达 &lt;cash&gt; 节点。您可以通过 .. 获取 xpath 中当前节点的父节点:

    SELECT  
    Result.Claim.value('(../@number)[1]','varchar(max)') as C1,
    Result.Claim.value('(./@amt)[1]','varchar(max)') as C2,
    Result.Claim.value('(./@status)[1]','varchar(max)') as C3   
    From @Innerxml.nodes('/result/cash/account') Result(Claim)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-02-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-14
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多