使用 SQL XML 获取所有值

Getting all values with SQL XML

我目前正在处理美国财政部的特别指定国民名单 (sdn) 示例:

<sdnList xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://tempuri.org/sdnList.xsd">
    <publshInformation>
        <Publish_Date>01/10/2022</Publish_Date>
        <Record_Count>9015</Record_Count>
    </publshInformation>
    <sdnEntry>
        <uid>18590</uid>
        <firstName>xxx</firstName>
        <lastName>xxx</lastName>
        <sdnType>Individual</sdnType>
        <programList>
            <program>SDGT</program>
        </programList>
        <idList>
            <id>
                <uid>10858</uid>
                <idType>Passport</idType>
                <idNumber>xxx</idNumber>
                <idCountry>Morocco</idCountry>
            </id>
            <id>
                <uid>10859</uid>
                <idType>National ID No.</idType>
                <idNumber>xxx</idNumber>
                <idCountry>Morocco</idCountry>
            </id>
        </idList>
        <akaList>
            <aka>
                <uid>28970</uid>
                <type>a.k.a.</type>
                <category>strong</category>
                <lastName>xxx</lastName>
                <firstName>xxx</firstName>
            </aka>
            <aka>
                <uid>28971</uid>
                <type>a.k.a.</type>
                <category>weak</category>
                <lastName>xxx</lastName>
            </aka>
            <aka>
                <uid>28972</uid>
                <type>a.k.a.</type>
                <category>weak</category>
                <lastName>xxx</lastName>
            </aka>
            <aka>
                <uid>28973</uid>
                <type>a.k.a.</type>
                <category>weak</category>
                <lastName>xxx</lastName>
            </aka>
        </akaList>
        <citizenshipList>
            <citizenship>
                <uid>17970</uid>
                <country>Morocco</country>
                <mainEntry>true</mainEntry>
            </citizenship>
        </citizenshipList>
        <dateOfBirthList>
            <dateOfBirthItem>
                <uid>17969</uid>
                <dateOfBirth>26 Feb 1993</dateOfBirth>
                <mainEntry>true</mainEntry>
            </dateOfBirthItem>
        </dateOfBirthList>
    </sdnEntry>
  /sdnList>

我的查询是:

;WITH XMLNAMESPACES
 (
     DEFAULT 'http://tempuri.org/sdnList.xsd'
 )

    SELECT x.n.value('uid[1]', 'int') AS UID,
           x.n.value('sdnType[1]', 'char(20)') AS SdnType,
           x.n.value('firstName[1]', 'varchar(200)') AS FirstName,
           x.n.value('lastName[1]', 'varchar(200)') AS LastName,
           x.n.value('./akaList[1]/aka[1]/lastName[1]', 'char(100)') AS akaLastName,
           x.n.value('./akaList[1]/aka[1]/firstName[1]', 'varchar(200)') AS AKAFirstName,
           x.n.value('./akaList[1]/aka[1]/lastName[1]', 'varchar(200)') AS AKALastName,
           x.n.value('./dateOfBirthList[1]/dateOfBirthItem[1]/dateOfBirth[1]', 'varchar(20)') AS DateOfBirth,
           x.n.value('./addressList[1]/address[1]/address1[1]', 'varchar(100)') AS Address1,
           x.n.value('./addressList[1]/address[1]/postalCode[1]', 'varchar(100)') AS PostCode,
           x.n.value('./addressList[1]/address[1]/city[1]', 'varchar(100)') AS City,
           x.n.value('./addressList[1]/address[1]/country[1]', 'varchar(100)') AS Country
    FROM @XMLData t
        CROSS APPLY t.XMLColumn.nodes('/sdnList/sdnEntry') x(n)

我当前的查询只检索每个实体的 aka 和地址的第一个条目。我知道这是因为我在查询中使用了 [1] 个单例,但不知道如何检索每个条目的所有子条目。我需要使用子查询吗?

XML 缺失 <addressList>

总的来说,辅助CROSS APPLY ...模拟了XML中的一对多关系。

SQL

DECLARE @XMLData TABLE (ID INT IDENTITY PRIMARY KEY, XMLColumn XML);
INSERT INTO @XMLData (XMLColumn) VALUES
(N'<sdnList xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://tempuri.org/sdnList.xsd">
    <publshInformation>
        <Publish_Date>01/10/2022</Publish_Date>
        <Record_Count>9015</Record_Count>
    </publshInformation>
    <sdnEntry>
        <uid>18590</uid>
        <firstName>xxx</firstName>
        <lastName>xxx</lastName>
        <sdnType>Individual</sdnType>
        <programList>
            <program>SDGT</program>
        </programList>
        <idList>
            <id>
                <uid>10858</uid>
                <idType>Passport</idType>
                <idNumber>xxx</idNumber>
                <idCountry>Morocco</idCountry>
            </id>
            <id>
                <uid>10859</uid>
                <idType>National ID No.</idType>
                <idNumber>xxx</idNumber>
                <idCountry>Morocco</idCountry>
            </id>
        </idList>
        <akaList>
            <aka>
                <uid>28970</uid>
                <type>a.k.a.</type>
                <category>strong</category>
                <lastName>xxx</lastName>
                <firstName>xxx</firstName>
            </aka>
            <aka>
                <uid>28971</uid>
                <type>a.k.a.</type>
                <category>weak</category>
                <lastName>xxx</lastName>
            </aka>
            <aka>
                <uid>28972</uid>
                <type>a.k.a.</type>
                <category>weak</category>
                <lastName>xxx</lastName>
            </aka>
            <aka>
                <uid>28973</uid>
                <type>a.k.a.</type>
                <category>weak</category>
                <lastName>xxx</lastName>
            </aka>
        </akaList>
        <citizenshipList>
            <citizenship>
                <uid>17970</uid>
                <country>Morocco</country>
                <mainEntry>true</mainEntry>
            </citizenship>
        </citizenshipList>
        <dateOfBirthList>
            <dateOfBirthItem>
                <uid>17969</uid>
                <dateOfBirth>26 Feb 1993</dateOfBirth>
                <mainEntry>true</mainEntry>
            </dateOfBirthItem>
        </dateOfBirthList>
    </sdnEntry>
</sdnList>');

;WITH XMLNAMESPACES
 (
     DEFAULT 'http://tempuri.org/sdnList.xsd'
 )
SELECT n.value('(uid/text())[1]', 'int') AS UID,
    n.value('(sdnType/text())[1]', 'char(20)') AS SdnType,
    n.value('(firstName/text())[1]', 'varchar(200)') AS FirstName,
    n.value('(lastName/text())[1]', 'varchar(200)') AS LastName,
    a.value('(lastName/text())[1]', 'char(100)') AS akaLastName,
    a.value('(firstName/text())[1]', 'varchar(200)') AS AKAFirstName,
    a.value('(lastName/text())[1]', 'varchar(200)') AS AKALastName,
    n.value('(dateOfBirthList/dateOfBirthItem/dateOfBirth/text())[1]', 'varchar(20)') AS DateOfBirth
    --x.n.value('./addressList[1]/address[1]/address1[1]', 'varchar(100)') AS Address1,
    --x.n.value('./addressList[1]/address[1]/postalCode[1]', 'varchar(100)') AS PostCode,
    --x.n.value('./addressList[1]/address[1]/city[1]', 'varchar(100)') AS City,
    --x.n.value('./addressList[1]/address[1]/country[1]', 'varchar(100)') AS Country
FROM @XMLData t
    CROSS APPLY t.XMLColumn.nodes('/sdnList/sdnEntry') AS t1(n)
    CROSS APPLY t1.n.nodes('akaList/aka') AS t2(a)