使用xquery从xml中提取数据的最佳方法

2023-12-30

考虑以下 xml:

<Persons num="3">
  <Person age="5" />
  <Person age="19" />
</Persons>

需要将此xml提取到关系表中:

Persons table (Age1 int, Age2 int, Age3 int , Age4 int)

解析必须满足以下约束:

  • 所有年龄 >=18 的人都必须分配到列号最小的列,并且该值必须为 18
  • 如果未给出该人的年龄,则等于 18 岁
  • 所有年龄
  • 如果少于4人,未提供的年龄必须=-1

在给定的示例中,有 3 个人,提供了其中 2 人的年龄:分别为 5 岁和 19 岁。 Persons 表的内容必须如下:

18 18 5 -1

有没有最好的方法来使用 xpath 来做到这一点?

到目前为止,我可以解析 xml 并分配年龄,但不清楚的是如何进行排序:

declare @XmlData xml = 
'<Persons num="3">
    <Person age="5" />
    <Person age="19" />
</Persons>'

declare @Persons table (Age1 int, Age2 int, Age3 int , Age4 int)
insert into @Persons (Age1, Age2, Age3, Age4)
select ISNULL(Age1, case when Num>= 1 then 18 else -1 end) Age1
    , ISNULL(Age2, case when Num>= 2 then 18 else -1 end) Age2
    , ISNULL(Age3, case when Num>= 3 then 18 else -1 end) Age3
    , ISNULL(Age4, case when Num>= 4 then 18 else -1 end) Age4
from (
    select Persons.Person.value('@num','smallint') as Num
          ,Persons.Person.value('Person[@age<18][1]/@age','smallint') as Age1
          ,Persons.Person.value('Person[@age<18][2]/@age','smallint') as Age2
          ,Persons.Person.value('Person[@age<18][3]/@age','smallint') as Age3
          ,Persons.Person.value('Person[@age<18][4]/@age','smallint') as Age4
    from @XmlData.nodes('/Persons') Persons(Person)
 ) Persons  

select *
from @Persons

结果是

5 18 18 -1

我发现了一个有点肮脏的解决方案:

select ISNULL(Age1, case when Num>= 1 then 18 else -1 end) Age1
    , ISNULL(Age2, case when Num>= 2 then 18 else -1 end) Age2
    , ISNULL(Age3, case when Num>= 3 then 18 else -1 end) Age3
    , ISNULL(Age4, case when Num>= 4 then 18 else -1 end) Age4
from (
    select Persons.Person.value('@num','smallint') as Num
          ,Persons.Person.value('xs:integer(fn:number(@num))+1','int') as Num1
          ,Persons.Person.value('Person[@age<18][xs:integer(fn:number(../@num))][1]/@age','smallint') as Age1
          ,Persons.Person.value('Person[@age<18][xs:integer(fn:number(../@num))-1][1]/@age','smallint') as Age2
          ,Persons.Person.value('Person[@age<18][xs:integer(fn:number(../@num))-2][1]/@age','smallint') as Age3
          ,Persons.Person.value('Person[@age<18][xs:integer(fn:number(../@num))-3][1]/@age','smallint') as Age4 
    from @XmlData.nodes('/Persons') Persons(Person)
 ) Persons

解决方案的想法是首先提取那些 >=18 的联系人,然后提取那些 0

UPD:尽管解决方案提供了正确的结果,但其成本很高:预计执行计划约为 1000

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用xquery从xml中提取数据的最佳方法 的相关文章

随机推荐