【问题标题】:XML to SQL - Selecting multiple nodes with the same nameXML to SQL - 选择同名的多个节点
【发布时间】:2020-09-10 18:47:30
【问题描述】:

我有可以从 XML 文件中选择一些值的工作代码。问题是我有多个同名节点。

这是 XML 的 sn-p:

<wd:Report_Data xmlns:wd="urn:com.workday.report/Countries_and_Their_Address_Components_Summary">
  <wd:Report_Entry>
    <wd:Country wd:Descriptor="Afghanistan">
      <wd:ID wd:type="WID">db69b722446c11de98360015c5e6daf6</wd:ID>
      <wd:ID wd:type="ISO_3166-1_Alpha-2_Code">AF</wd:ID>
      <wd:ID wd:type="ISO_3166-1_Alpha-3_Code">AFG</wd:ID>
      <wd:ID wd:type="ISO_3166-1_Numeric-3_Code">4</wd:ID>
    </wd:Country>
    <wd:Address_Format_Type wd:Descriptor="Basic">
      <wd:ID wd:type="WID">4516bf435611423ea4ee72fa842572a0</wd:ID>
    </wd:Address_Format_Type>
    <wd:Local>1</wd:Local>
    <wd:Address_Components>
      <wd:Address_Component wd:Descriptor="Address Line 1 - Local">
        <wd:ID wd:type="WID">12d859b8df024175a111da2e088250fb</wd:ID>
        <wd:ID wd:type="Address_Component_Type_ID">ADDRESS_LINE_1_LOCAL</wd:ID>
      </wd:Address_Component>
      <wd:Order>a</wd:Order>
      <wd:Required>0</wd:Required>
    </wd:Address_Components>
    <wd:Address_Components>
      <wd:Address_Component wd:Descriptor="Address Line 2 - Local">
        <wd:ID wd:type="WID">85a6ab9412c44dd9a71a7e4760bf17fb</wd:ID>
        <wd:ID wd:type="Address_Component_Type_ID">ADDRESS_LINE_2_LOCAL</wd:ID>
      </wd:Address_Component>
      <wd:Order>b</wd:Order>
      <wd:Required>0</wd:Required>
    </wd:Address_Components>

我的 SQL 如下:

declare @inputxml table (x xml)

insert @inputxml
select x
from OPENROWSET(BULK 'C:\ParallelTool\addcomp.xml', SINGLE_BLOB) As T(x)

;WITH XMLNAMESPACES(DEFAULT 'urn:com.workday.report/Countries_and_Their_Address_Components_Summary')
    select 
        xmldata.[ISO], xmldata.[Component 1], xmldata.[Component 2], xmldata.[Required]
    into dbo.WD
    from @inputxml
    cross apply (
        select 
            [ISO] = xmldata.value('(Country/ID)[3]', 'VARCHAR(MAX)'),
            [Component 1] = xmldata.value('(Address_Components/Address_Component/ID)[2]', 'VARCHAR(MAX)'),
            [Component 2] = xmldata.value('(Address_Components/Address_Component/ID)[2]', 'VARCHAR(MAX)'),
            [Required] = xmldata.value('(Address_Components/Required)[1]', 'INT')
        from x.nodes('/Report_Data/Report_Entry') Z1(xmldata)
    ) xmldata

我无法获得所需的是 [组件 2]。我想基本上选择文件中的所有“Address_Component_Type_ID”,但它们的名称都相同,并且在其他名称相同的节点下。如何在我的 SQL 中指定获取所有组件类型?感谢您的关注!

【问题讨论】:

    标签: sql sql-server xml


    【解决方案1】:

    取决于你想做什么......如果你知道你想要抓取的正是 2 个“Address_Components”,你可以像这样修改你的查询:

    ;WITH XMLNAMESPACES(DEFAULT 'urn:com.workday.report/Countries_and_Their_Address_Components_Summary')
        select 
            xmldata.[ISO], xmldata.[Component 1], xmldata.[Component 2], xmldata.[Required]
        from @inputxml
        cross apply (
            select 
                [ISO] = xmldata.value('(Country/ID)[3]', 'VARCHAR(MAX)'),
                [Component 1] = xmldata.value('(Address_Components/Address_Component/ID)[2]', 'VARCHAR(MAX)'),
                [Component 2] = xmldata.value('(Address_Components[2]/Address_Component/ID)[2]', 'VARCHAR(MAX)'),
                [Required] = xmldata.value('(Address_Components/Required)[1]', 'INT')
            from x.nodes('/Report_Data/Report_Entry') Z1(xmldata)
        ) xmldata
    

    结果如下所示:

    ISO   Component 1               Component 2               Required
    ----- ------------------------- ------------------------- -----------
    AFG   ADDRESS_LINE_1_LOCAL      ADDRESS_LINE_2_LOCAL      0
    

    但是,如果可以有任意数量的“Address_Components”,并且您想将它们抓取到单独的记录中,您可以像这样重写您的查询:

    ;WITH XMLNAMESPACES(DEFAULT 'urn:com.workday.report/Countries_and_Their_Address_Components_Summary')
        select 
            [ISO] = Report_Entry.x.value('(Country/ID)[3]', 'VARCHAR(MAX)')
            , [Component] = Address_Components.x.value('(Address_Component/ID)[2]', 'VARCHAR(MAX)')
            , [Required] = Address_Components.x.value('(Required)[1]', 'INT')
        from @inputxml
        cross apply x.nodes('/Report_Data/Report_Entry') Report_Entry(x)
        cross apply Report_Entry.x.nodes('./Address_Components') Address_Components (x)
    

    结果如下所示:

    ISO   Component                 Required
    ----- ------------------------- -----------
    AFG   ADDRESS_LINE_1_LOCAL      0
    AFG   ADDRESS_LINE_2_LOCAL      0
    

    【讨论】:

    • 这很棒。这绝对是朝着我需要的正确方向迈出的一大步。您无法通过我链接的 sn-p 来判断,但我实际上有多个 ISO。出于这个原因,当我使用交叉应用时,我将所有内容相乘以包含重复项。我得到的不是只有 1300 行,而是 299,000 行(230 ISO * 1300 地址组件)。它本质上是交叉应用到每个节点,而不仅仅是当前节点中的节点。我已经玩了一段时间了,没有运气。有没有办法让它只在当前 ISO 中交叉应用?
    • 为了进一步澄清,它并不完全重复。我措辞不正确-它们似乎是重复的。但它所做的是抓取文件中的每个地址组件并将其应用到每个 ISO,我只需要来自相应 ISO 内的地址组件。
    • @bheltzel 你是对的。我写交叉的方式适用于 Address_Components,它从根中提取所有地址组件,而不仅仅是当前 ISO 元素的子元素。我现在更正了。如果对您有用,请将答案标记为正确。
    • 漂亮!!非常感谢。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-09-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多