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

标签 xml sql-server-2008 xquery-sql

考虑以下 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 岁
  • 所有年龄 <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 < age < 18的联系人,最后将没有提供的设置为-1

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

关于xml - 使用 xquery 从 xml 中提取数据的最佳方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6070256/

相关文章:

android - 找不到属性 'menu' 的资源标识符

xml - 如何验证 xml 的语法/格式是否正确(?)

java - 从 XMLBean 中删除属性

sql - 从脚本中获取 sql 日志文件名

sql-server - 从另一个存储过程调用 SQLCLR 过程并获得 2 个返回值?

xml - 如何在t-sql中连接peer节点的值

sql - 在 SQL Server 中检索具有相同前缀的所有 XML 元素

java - 一个模式不能包含两个同名的全局组件

sql-server-2008 - Access 查询运行缓慢

sql - 如何在 SQL Server 中选择 XML 列的顶级属性?