【问题标题】:Shred XML into multiple rows in SQL在 SQL 中将 XML 分解为多行
【发布时间】:2019-04-16 18:11:42
【问题描述】:

我必须每两周切碎一个 XML 文档。它符合NEMSIS 2 标准,我有一个兼容的数据库来保存信息。我已经成功构建了一个查询来导入所有一对一数据,但是我在分解一对多数据时遇到了麻烦。

使用此演示数据:

declare @x xml  
set @x =  
'<EMSDataSet>  
    <Header>  
    <D01_01>abc</D01_01>  
        <Record>  
            <E01>  
                <E01_01>12345</E01_01>  
                <E01_02>678</E01_02>  
            </E01>  
            <E02>  
                <E02_01>123</E02_01>  
                <E02_09>295</E02_09>  
                <E02_09>296</E02_09>  
            </E02>  
        </Record>
        <Record>
            <E01>
                <E01_01>67890</E01_01>
                <E01_02>678</E01_02>
            </E01>
            <E02>
                <E02_01>123</E02_01>
                <E02_09>295</E02_09>                
            </E02>
        </Record>  
    </Header>  
</EMSDataSet>'  

此查询正确返回正确的值 01_01 和第一个值 02_09。但是,由于 Value() 只能返回一个单例,所以我只能得到第一个值:

Query:  
select  
    t.c.value('(E01/E01_01)[1]','varchar(max)') e01_01  
   ,t.c.value('(E02/E02_09)[1]','varchar(max)') e02_09  
from @x.nodes('EMSDataSet/Header/Record') t(c)  

Returns:  
e01_01     e02_09  
------     ------  
 12345        295  

此查询在各自的行中返回 02_09 值,但没有对应的 01_01 值:

Query:  
select  
    t2.c.value('.','varchar(max)') e02_09  
from @x.nodes('EMSDataSet/Header/Record/E02/E02_09') t2(c)  

Returns:  
e02_09  
 -----  
   295  
   296  

我需要完成的是合并结果并将值 02_09 的两个值与值 01_01 在每一行上重复。值 01_01 将充当数据库中的外键,引用特定的唯一事件。

e01_01     e02_09  
------     ------  
 12345        295  
 12345        296  

看起来它可能需要使用 Nodes() 方法和可能的 Join,但我无法弄清楚获取单个值 01_01 值的语法对每个值重复 02_09 值。

这些问题/答案让我走到了这一步:

Retrieve-all-child-nodes-from-a-parent-node-xml-sql-server
Returning multiple rows from querying XML column in SQL Server 2008
T-SQL Shred Second Level XML Nodes into Multiple Rows
Shred XML For Each Row in SQL Table

编辑: 在早期成功后,我尝试遵循代码。但是,它没有从我的测试数据集中返回正确的 36 行(35 条记录,重复 e02_09 的双精度值),而是返回了 1260 条记录(36 行 * 35 行)。

select *
from
    (
      select 
          t.c.value('(E01/E01_01)[1]','varchar(max)') e01_01
      from @x.nodes('EMSDataSet/Header/Record') t(c)
    ) a
    ,
    (
      select
          t2.c.value('.','varchar(max)') e02_09
      from @x.nodes('EMSDataSet/Header/Record/E02/E02_09') t2(c)
    ) b

【问题讨论】:

  • 我通常使用c#之类的编程语言来做解析。
  • 不幸的是,这不是我的选择。我需要将数据直接从文件移动到 SQL。任何想法表示赞赏。

标签: sql-server xml tsql sql-server-2012 xml-parsing


【解决方案1】:

我能够获得的最佳答案基于此blog post by Adam Machanic

select 
    e01_01
    ,e02_09
from
    (select 
        dense_rank() over (order by b_node) unique_b_node
        ,c_node.value('./text()[1]','varchar(max)') e02_09

    from @x.nodes('/EMSDataSet/Header/Record') b(b_node)
    cross apply b.b_node.nodes('./E02/E02_09') c(c_node)
    ) a
join
    (select
        dense_rank() over (order by b2.b_node) unique_b_node
        ,c_node.value('text()[1]','varchar(max)') e01_01
    from @x.nodes('/EMSDataSet/Header/Record') b2(b_node)
    cross apply b2.b_node.nodes('./E01/E01_01') c2(c_node)
    ) b
on a.unique_b_node = b.unique_b_node

【讨论】:

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