繁体   English   中英

使用重复的标签解析 SQL 中的 XML 文件

[英]Parse XML file in SQL with duplicated Tags

我正在尝试展平我的 XML 文件,但是当标签中有重复标签时会出现并发症。 我不确定如何向上移动标签链。 下面的例子。

DECLARE @xml AS XMl, @hDoc AS INT
SET @xml = '<Message>
    <Body>
        <SfkpgAcctAndHldgs>
            <SfkpgAcct>UHS5465</SfkpgAcct>
            <AcctSubLvl>
                <Dsclsr>
                    <SfkpgAcct>450812361</SfkpgAcct>
                    <AcctHldr>
                        <LglPrsn>
                            <NmAndAdr>
                                <Nm>Foo</Nm>
                                <Adr>
                                    <AdrLine>1 CORPORATE WAY, New York 15951</AdrLine>
                                    <Ctry>US</Ctry>
                                </Adr>
                            </NmAndAdr>
                            <LEI>5493231HPIWHJS5QL7N39</LEI>
                            <Ownrsh>OWNR</Ownrsh>
                        </LglPrsn>
                    </AcctHldr>
                    <ShrhldgBal>
                        <ShrhldgTp>BENE</ShrhldgTp>
                        <Unit>1000</Unit>
                    </ShrhldgBal>
                </Dsclsr>
                <Dsclsr>
                    <SfkpgAcct>450812362</SfkpgAcct>
                    <AcctHldr>
                        <LglPrsn>
                            <NmAndAdr>
                                <Nm>Bar</Nm>
                                <Adr>
                                    <AdrLine>2 CORPORATE WAY</AdrLine>
                                    <AdrLine>New York</AdrLine>
                                    <AdrLine>15951</AdrLine>
                                    <Ctry>US</Ctry>
                                </Adr>
                            </NmAndAdr>
                            <LEI>5493231HP2342345QL7N39</LEI>
                            <Ownrsh>OWNR</Ownrsh>
                        </LglPrsn>
                    </AcctHldr>
                    <ShrhldgBal>
                        <ShrhldgTp>BENE</ShrhldgTp>
                        <Unit>300</Unit>
                    </ShrhldgBal>
                </Dsclsr>
            </AcctSubLvl>
        </SfkpgAcctAndHldgs>        
    </Body>
</message>'
EXEC sp_xml_preparedocument @hDoc OUTPUT, @XML 

此查询获取每个 SfkpgAcctAndHldgs 并引入第一个 Dsclsr,有两个但只有第一个返回。

    SELECT * 
    FROM OPENXML(@hDoc,'message/Body/SfkpgAcctAndHldgs') WITH (
          SfkpgAcct                                                     NVARCHAR(MAX)   'SfkpgAcct'
        , Dsclsr_SfkpgAcct                                              NVARCHAR(MAX)   'AcctSubLvl/Dsclsr/SfkpgAcct'
        , Dsclsr_AcctHldr_LglPrsn_NmAndAdr_Nm                           NVARCHAR(MAX)   'AcctSubLvl/Dsclsr/AcctHldr/LglPrsn/NmAndAdr/Nm'
        , Dsclsr_AcctHldr_LglPrsn_NmAndAdr_Adr_AdrLine                  NVARCHAR(MAX)   'AcctSubLvl/Dsclsr/AcctHldr/LglPrsn/NmAndAdr/Adr/AdrLine'
        , Dsclsr_AcctHldr_LglPrsn_NmAndAdr_Adr_Ctry                     NVARCHAR(MAX)   'AcctSubLvl/Dsclsr/AcctHldr/LglPrsn/NmAndAdr/Adr/Ctry'
        , Dsclsr_AcctHldr_LglPrsn_LEI                                   NVARCHAR(MAX)   'AcctSubLvl/Dsclsr/AcctHldr/LglPrsn/LEI'
        , Dsclsr_AcctHldr_LglPrsn_Ownrsh                                NVARCHAR(MAX)   'AcctSubLvl/Dsclsr/AcctHldr/LglPrsn/Ownrsh'
        , Dsclsr_ShrhldgBal_ShrhldgTp                                   NVARCHAR(MAX)   'AcctSubLvl/Dsclsr/ShrhldgBal/ShrhldgTp'
        , Dsclsr_ShrhldgBal_Unit                                        NVARCHAR(MAX)   'AcctSubLvl/Dsclsr/ShrhldgBal/Unit'
        )
--SfkpgAcct AcctSubLvl_Dsclsr_SfkpgAcct Dsclsr_AcctHldr_LglPrsn_NmAndAdr_Nm Dsclsr_AcctHldr_LglPrsn_NmAndAdr_Adr_AdrLine    Dsclsr_AcctHldr_LglPrsn_NmAndAdr_Adr_Ctry   Dsclsr_AcctHldr_LglPrsn_LEI Dsclsr_AcctHldr_LglPrsn_Ownrsh  Dsclsr_AcctHldr_ShrhldgBal_ShrhldgTp    Dsclsr_AcctHldr_ShrhldgBal_Unit
--UHS5465   450812361                   Foo                                 1 CORPORATE WAY, New York 15951                 US  5493231                                 HPIWHJS5QL7N39              OWNR                            BENE                                    1000

此查询查看 Dsclsr 级别,因此带回了这两行。 但是我不能 go 备份链以获得第一个 SfkpgAcct 值,这是我可以加入表格的唯一值。


    SELECT * 
    FROM OPENXML(@hDoc,'message/Body/SfkpgAcctAndHldgs/AcctSubLvl/Dsclsr') WITH (
          SfkpgAcct                                                     NVARCHAR(MAX)   'SfkpgAcct'
        , AcctHldr_LglPrsn_NmAndAdr_Nm                                  NVARCHAR(MAX)   'AcctHldr/LglPrsn/NmAndAdr/Nm'
        , AcctHldr_LglPrsn_NmAndAdr_Adr_AdrLine                         NVARCHAR(MAX)   'AcctHldr/LglPrsn/NmAndAdr/Adr/AdrLine'
        , AcctHldr_LglPrsn_NmAndAdr_Adr_Ctry                            NVARCHAR(MAX)   'AcctHldr/LglPrsn/NmAndAdr/Adr/Ctry'
        , AcctHldr_LglPrsn_LEI                                          NVARCHAR(MAX)   'AcctHldr/LglPrsn/LEI'
        , AcctHldr_LglPrsn_Ownrsh                                       NVARCHAR(MAX)   'AcctHldr/LglPrsn/Ownrsh'
        , ShrhldgBal_ShrhldgTp                                          NVARCHAR(MAX)   'ShrhldgBal/ShrhldgTp'
        , ShrhldgBal_Unit                                               NVARCHAR(MAX)   'ShrhldgBal/Unit'
        )

--SfkpgAcct AcctHldr_LglPrsn_NmAndAdr_Nm    AcctHldr_LglPrsn_NmAndAdr_Adr_AdrLine   AcctHldr_LglPrsn_NmAndAdr_Adr_Ctry  AcctHldr_LglPrsn_LEI    AcctHldr_LglPrsn_Ownrsh ShrhldgBal_ShrhldgTp    ShrhldgBal_Unit
--450812361 Foo                             1 CORPORATE WAY, New York 15951         US                                  5493231HPIWHJS5QL7N39   OWNR                    BENE                    1000
--450812362 Bar                             2 CORPORATE WAY                         US                                  5493231HP2342345QL7N39  OWNR                    BENE                    300

有时也有多个 AdrLine 字段,但是在与上述相同的示例中,我不知道谁来 go 备份链以引用任何以前的值,以便我可以加入。

    SELECT * 
    FROM OPENXML(@hDoc,'message/Body/SfkpgAcctAndHldgs/AcctSubLvl/Dsclsr/AcctHldr/LglPrsn/NmAndAdr/Adr/AdrLine') WITH (
          AcctHldr_LglPrsn_NmAndAdr_Adr_AdrLine                         NVARCHAR(MAX)   '.'
        )
--AcctHldr_LglPrsn_NmAndAdr_Adr_AdrLine
--1 CORPORATE WAY, New York 15951
--2 CORPORATE WAY
--New York
--15951

EXEC sp_xml_removedocument @hDoc

理想情况下,我想要一个平面文件中的所有值,我可以使用视图将各个表连接在一起,前提是我可以赋予现有 ID 或生成新 ID。

--SfkpgAcct     DsclsrSfkpgAcct Nm      AdrLine1                        AdrLine2    AdrLine3    Ctry    LEI                     Ownrsh      ShrhldgTp   Unit
--UHS5465       450812361       Foo     1 CORPORATE WAY, New York 15951                         US      5493231HPIWHJS5QL7N39   OWNR        BENE        1000
--UHS5465       450812362       Bar     2 CORPORATE WAY                 New York    15951       US      5493231HP2342345QL7N39  OWNR        BENE        300
                                 

保留 Microsoft 专有的OPENXML()及其伙伴sp_xml_preparedocumentsp_xml_removedocument只是为了与过时的 SQL Server 2000 向后兼容。它们的使用减少到很少的边缘情况。 从 SQL Server 2005 开始,强烈建议重新编写您的 SQL 并将其切换到 XQuery。

SQL

DECLARE @xml XML =
N'<Message>
    <Body>
        <SfkpgAcctAndHldgs>
            <SfkpgAcct>UHS5465</SfkpgAcct>
            <AcctSubLvl>
                <Dsclsr>
                    <SfkpgAcct>450812361</SfkpgAcct>
                    <AcctHldr>
                        <LglPrsn>
                            <NmAndAdr>
                                <Nm>Foo</Nm>
                                <Adr>
                                    <AdrLine>1 CORPORATE WAY, New York 15951</AdrLine>
                                    <Ctry>US</Ctry>
                                </Adr>
                            </NmAndAdr>
                            <LEI>5493231HPIWHJS5QL7N39</LEI>
                            <Ownrsh>OWNR</Ownrsh>
                        </LglPrsn>
                    </AcctHldr>
                    <ShrhldgBal>
                        <ShrhldgTp>BENE</ShrhldgTp>
                        <Unit>1000</Unit>
                    </ShrhldgBal>
                </Dsclsr>
                <Dsclsr>
                    <SfkpgAcct>450812362</SfkpgAcct>
                    <AcctHldr>
                        <LglPrsn>
                            <NmAndAdr>
                                <Nm>Bar</Nm>
                                <Adr>
                                    <AdrLine>2 CORPORATE WAY</AdrLine>
                                    <AdrLine>New York</AdrLine>
                                    <AdrLine>15951</AdrLine>
                                    <Ctry>US</Ctry>
                                </Adr>
                            </NmAndAdr>
                            <LEI>5493231HP2342345QL7N39</LEI>
                            <Ownrsh>OWNR</Ownrsh>
                        </LglPrsn>
                    </AcctHldr>
                    <ShrhldgBal>
                        <ShrhldgTp>BENE</ShrhldgTp>
                        <Unit>300</Unit>
                    </ShrhldgBal>
                </Dsclsr>
            </AcctSubLvl>
        </SfkpgAcctAndHldgs>
    </Body>
</Message>';

SELECT c.value('(SfkpgAcct/text())[1]', 'VARCHAR(20)') AS SfkpgAcct
    , x.value('(SfkpgAcct/text())[1]', 'VARCHAR(20)') AS DsclsrSfkpgAcct
    , x.value('(AcctHldr/LglPrsn/NmAndAdr/Nm/text())[1]', 'VARCHAR(20)') AS Nm
    , x.value('(AcctHldr/LglPrsn/NmAndAdr/Adr/AdrLine[1]/text())[1]', 'VARCHAR(50)') AS AdrLine1
    , x.value('(AcctHldr/LglPrsn/NmAndAdr/Adr/AdrLine[2]/text())[1]', 'VARCHAR(50)') AS AdrLine2
    , x.value('(AcctHldr/LglPrsn/NmAndAdr/Adr/AdrLine[3]/text())[1]', 'VARCHAR(50)') AS AdrLine3
    , x.value('(AcctHldr/LglPrsn/NmAndAdr/Adr/Ctry/text())[1]', 'VARCHAR(50)') AS Ctry
    , x.value('(AcctHldr/LglPrsn/LEI/text())[1]', 'VARCHAR(50)') AS LEI
    , x.value('(AcctHldr/LglPrsn/Ownrsh/text())[1]', 'VARCHAR(50)') AS Ownrsh
    , x.value('(ShrhldgBal/ShrhldgTp/text())[1]', 'VARCHAR(50)') AS ShrhldgTp
    , x.value('(ShrhldgBal/Unit/text())[1]', 'VARCHAR(50)') AS Unit
FROM @xml.nodes('/Message/Body/SfkpgAcctAndHldgs') AS t1(c)
    CROSS APPLY t1.c.nodes('AcctSubLvl/Dsclsr') AS t2(x);

Output

+-----------+-----------------+-----+---------------------------------+----------+----------+------+------------------------+--------+-----------+------+
| SfkpgAcct | DsclsrSfkpgAcct | Nm  |            AdrLine1             | AdrLine2 | AdrLine3 | Ctry |          LEI           | Ownrsh | ShrhldgTp | Unit |
+-----------+-----------------+-----+---------------------------------+----------+----------+------+------------------------+--------+-----------+------+
| UHS5465   |       450812361 | Foo | 1 CORPORATE WAY, New York 15951 | NULL     | NULL     | US   | 5493231HPIWHJS5QL7N39  | OWNR   | BENE      | 1000 |
| UHS5465   |       450812362 | Bar | 2 CORPORATE WAY                 | New York | 15951    | US   | 5493231HP2342345QL7N39 | OWNR   | BENE      |  300 |
+-----------+-----------------+-----+---------------------------------+----------+----------+------+------------------------+--------+-----------+------+

在 MS SQL 服务器中处理 XML 是一件痛苦的事情……恕我直言。 反正:

SELECT SfkpgAcct,
       Dsclsr_SfkpgAcct,
       Dsclsr_AcctHldr_LglPrsn_NmAndAdr_Nm,
       Dsclsr_AcctHldr_LglPrsn_NmAndAdr_Adr_AdrLine1,
       Dsclsr_AcctHldr_LglPrsn_NmAndAdr_Adr_AdrLine2,
       Dsclsr_AcctHldr_LglPrsn_NmAndAdr_Adr_AdrLine3,
       Dsclsr_AcctHldr_LglPrsn_NmAndAdr_Adr_Ctry,
       Dsclsr_AcctHldr_LglPrsn_LEI,
       Dsclsr_AcctHldr_LglPrsn_Ownrsh,
       Dsclsr_ShrhldgBal_ShrhldgTp,
       Dsclsr_ShrhldgBal_Unit
FROM
    OPENXML(@hDoc, 'message/Body/SfkpgAcctAndHldgs')
    WITH
    (
        SfkpgAcct NVARCHAR(MAX) 'SfkpgAcct',
        AcctSubLvl XML 'AcctSubLvl'
    ) t1
    CROSS APPLY
(
    SELECT item.row.value('SfkpgAcct[1]', 'nvarchar(max)'),
           item.row.value('AcctHldr[1]/LglPrsn[1]/NmAndAdr[1]/Nm[1]', 'nvarchar(max)'),
           item.row.value('AcctHldr[1]/LglPrsn[1]/NmAndAdr[1]/Adr[1]/AdrLine[1]', 'nvarchar(max)'),
           item.row.value('AcctHldr[1]/LglPrsn[1]/NmAndAdr[1]/Adr[1]/AdrLine[2]', 'nvarchar(max)'),
           item.row.value('AcctHldr[1]/LglPrsn[1]/NmAndAdr[1]/Adr[1]/AdrLine[3]', 'nvarchar(max)'),
           item.row.value('AcctHldr[1]/LglPrsn[1]/NmAndAdr[1]/Adr[1]/Ctry[1]', 'nvarchar(max)'),
           item.row.value('AcctHldr[1]/LglPrsn[1]/LEI[1]', 'nvarchar(max)'),
           item.row.value('AcctHldr[1]/LglPrsn[1]/Ownrsh[1]', 'nvarchar(max)'),
           item.row.value('ShrhldgBal[1]/ShrhldgTp[1]', 'nvarchar(max)'),
           item.row.value('ShrhldgBal[1]/Unit[1]', 'nvarchar(max)')
    FROM t1.AcctSubLvl.nodes('AcctSubLvl/Dsclsr') item(row)
) AS nodes(Dsclsr_SfkpgAcct
    , Dsclsr_AcctHldr_LglPrsn_NmAndAdr_Nm
    , Dsclsr_AcctHldr_LglPrsn_NmAndAdr_Adr_AdrLine1
    , Dsclsr_AcctHldr_LglPrsn_NmAndAdr_Adr_AdrLine2
    , Dsclsr_AcctHldr_LglPrsn_NmAndAdr_Adr_AdrLine3
    , Dsclsr_AcctHldr_LglPrsn_NmAndAdr_Adr_Ctry
    , Dsclsr_AcctHldr_LglPrsn_LEI
    , Dsclsr_AcctHldr_LglPrsn_Ownrsh
    , Dsclsr_ShrhldgBal_ShrhldgTp
    , Dsclsr_ShrhldgBal_Unit);

DBFiddle 演示

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM