从重复元素及其子元素\属性中获取一张表中的多条XML记录

Posted

技术标签:

【中文标题】从重复元素及其子元素\\属性中获取一张表中的多条XML记录【英文标题】:Get multiple XML records in one table from a repeated element and its subelements \ attributes从重复元素及其子元素\属性中获取一张表中的多条XML记录 【发布时间】:2020-07-06 09:16:35 【问题描述】:

目前的算法使用 ... ,x.n.value ... [1] 方法,它只检索第一条记录。用什么更好地检索所有现有元素的值(以及层次结构中的其他记录)?

主要的 XML 提取基于类似的模型

SELECT..
CAST(decompress([Data]) AS NVARCHAR(MAX)

FROM.. 

然后去:

 ;WITH XMLNAMESPACES (DEFAULT 'urn://somenamespacename')
  INSERT INTO  [DB].[dbo].[table] (

ID
,Att1
,Att2
,SubAtt1
,SubAtt2
,Lenght
,Neighbour

)

SELECT

@ID
,x.n.value('(@Att1)[1]', 'VARCHAR(100)')
,x.n.value('(@Att2)[1]', 'VARCHAR(100)')
,x.n.value('(*:Neighbours/*:SubBorder/@SubAtt1)[1]', 'VARCHAR(100)')
,x.n.value('(*:Neighbours/*:SubBorder/@SubAtt2)[1]', 'VARCHAR(100)')
,x.n.value('(*:Edge/*:Lenght)[1]', 'int')
,x.n.value('(*:Edge/*:Neighbour)[1]',  'VARCHAR(100)')

FROM @xml.nodes('/root/*:TOP/*:Border')  as x(n)

XML 示例

<root>
    <TOP ID="1">
     <Border Att1="BorderValue1" Att2="BorderValue2">
       <Edge>
         <Length>100</Length>
         <Neighbours>
           <Neighbour>alpha</Neighbour>
           <SubBorder SubAtt1="SubValue1" SubAtt2="SubValue2" />
         </Neighbours>
       </Edge>
      </Border>

      <Border Att1="BorderValue3" Att1="BorderValue4">
       <Edge>
         <Length>300</Length>
         <Neighbours>
           <Neighbour>bravo</Neighbour>
           <SubBorder SubAtt1="SubValue3" SubAtt2="SubValue4" />
         </Neighbours>
       </Edge>
      </Border>
    </TOP>
</root>

期望的输出

ID      Att1          Att2         SubAtt1    SubAtt2    Lenght    Neighbour       
 1   BorderValue1 BorderValue2    SubValue1  SubValue2   100        alpha
 1   BorderValue3 BorderValue4    SubValue3  SubValue4   300        bravo

【问题讨论】:

【参考方案1】:

您正在声明一个命名空间,但 XML 中没有命名空间部分... 此外,还有一个双重属性“Att1”,估计是错字

但是,您似乎正在寻找.nodes()。此函数检索派生表中的重复元素:

您的 XML(没有命名空间):

DECLARE @xml XML=
N'<root>
    <TOP ID="1">
     <Border Att1="BorderValue1" Att2="BorderValue2">
       <Edge>
         <Length>100</Length>
         <Neighbours>
           <Neighbour>alpha</Neighbour>
           <SubBorder SubAtt1="SubValue1" SubAtt2="SubValue2" />
         </Neighbours>
       </Edge>
      </Border>

      <Border Att1="BorderValue3" Att2="BorderValue4">
       <Edge>
         <Length>300</Length>
         <Neighbours>
           <Neighbour>bravo</Neighbour>
           <SubBorder SubAtt1="SubValue3" SubAtt2="SubValue4" />
         </Neighbours>
       </Edge>
      </Border>
    </TOP>
</root>';

--查询

SELECT @xml.value('(/root/TOP/@ID)[1]','int') AS ID
      ,brd.value('@Att1','nvarchar(max)') AS Att1
      ,brd.value('@Att2','nvarchar(max)') AS Att2
      ,brd.value('(Edge/Length/text())[1]','decimal(10,4)') AS [Length]
      ,nghbs.value('(Neighbour/text())[1]','nvarchar(max)') AS Border_Neighbour
      ,nghbs.value('(SubBorder/@SubAtt1)[1]','nvarchar(max)') AS Border_SubAtt1
      ,nghbs.value('(SubBorder/@SubAtt2)[1]','nvarchar(max)') AS Border_SubAtt2
FROM @xml.nodes('root/TOP/Border') ATU_2x_check(brd)
OUTER APPLY brd.nodes('Edge/Neighbours') B(nghbs);

简而言之:

我们可以直接挑ID(不重复) 我们使用.nodes() 来获得重复的&lt;Border&gt; 元素 我们可以更深入地研究使用带有相对 XPath 的 .nodes() 重复 &lt;Neighbours&gt; 我们可以使用.value() 来读取给定片段的值。

【讨论】:

@Shnugo谢谢!我是否正确理解,对于所有元素的正确解析,使用层次结构中的最低元素进行外部应用就足够了?在这种情况下,您不需要额外的外部应用(例如,使用 Length 元素) 普通构造'.value...nvarchar(max)')和构造(/text())[1]','nvarchar(max)之间有显着区别吗?两种方法我都试过了,结果是一样的。 @XSLT-explorer,您需要 nodes() 来检索作为派生集的重复节点,并且对于单个值(相对于当前节点的任何单例 xpath)不需要它。 /text() 将加快查询速度,在这种情况下您需要它:&lt;a&gt;a1&lt;b&gt;inner&lt;/b&gt;a2&lt;/a&gt;a1a2&lt;a&gt; 下方的不同文本节点

以上是关于从重复元素及其子元素\属性中获取一张表中的多条XML记录的主要内容,如果未能解决你的问题,请参考以下文章

SQL关联两张表查数据,结果只显示一条。

数据库一张表中的名词定义

PL/SQL:循环遍历 XML 列并从重复元素中提取值

Oracle中的多行插入查询(从一张表中选择多行并插入到另一张表中[重复]

oracle中从一张表中筛选出不再多个时间段内的时间

mysql学习之路_高级数据操作