SQL Server XML querying: Query multiple child elements with same name

£可爱£侵袭症+ 提交于 2020-03-23 09:51:43

问题


In a previous question I wanted to know how I can use SQL to JOIN different XML elements based on an identifier. I was provided with several nice solutions as you can see here.

Now I am in the process of adapting this solution to my actual data. Unfortunately I stumbled upon a new obstacle that was not present in the minimum viable example I provided in the linked question. In my actual data I also have several child elements of the same name. See the element <subElement> in the following example data.

<xml>
    <dataSetData>
        <text>ABC</text>
    </dataSetData>
    <generalData>
        <id>123</id>
        <text>text data</text>
        <subElement>
            <subData>sub example data AAA</subData>
        </subElement>
        <subElement>
            <subData>sub example data BBB</subData>
        </subElement>
    </generalData>
    <generalData>
        <id>456</id>
        <text>text data 2</text>
        <subElement>
            <subData>sub example data CCC</subData>
        </subElement>
    </generalData>
    <specialData>
        <id>123</id>
        <text>special data text</text>
    </specialData>
    <specialData>
        <id>456</id>
        <text>special data text 2</text>
    </specialData>
</xml>

The expected result should look as follows.

DataSetData | GeneralDataID | GeneralDataText | subData              | SpecialDataTest
ABC         | 123           | text data       | sub example data AAA | special data text
ABC         | 123           | text data       | sub example data BBB | special data text
ABC         | 456           | text data  2    | sub example data CCC | special data text 2

The current solution (without considering the <subElement> data) is as follows (taken from here):

SELECT TheXml.value('(/xml/dataSetData/text/text())[1]', 'VARCHAR(20)') AS DataSetData
     ,B.*
    , sp.value('(id/text())[1]', 'INT') AS SpecialDataID 
    , sp.value('(text/text())[1]', 'VARCHAR(30)') AS SpecialDataTest
INTO dbo.TestResult4
FROM dbo.TestXml
CROSS APPLY TheXml.nodes('/xml/generalData') AS A(g)
CROSS APPLY(SELECT g.value('(id/text())[1]', 'INT') AS GeneralDataID 
                 , g.value('(text/text())[1]', 'VARCHAR(30)') AS GeneralDataText) B
OUTER APPLY TheXml.nodes('/xml/specialData[id=sql:column("B.GeneralDataID")]') AS special(sp);

回答1:


Okay, that was pretty straight forward...

SELECT TheXml.value('(/xml/dataSetData/text/text())[1]', 'VARCHAR(20)') AS DataSetData
    , B.*
    , se.value('(subData/text())[1]','varchar(100)') AS SubData 
    , sp.value('(id/text())[1]', 'INT') AS SpecialDataID 
    , sp.value('(text/text())[1]', 'VARCHAR(30)') AS SpecialDataTest
FROM dbo.TestXml
CROSS APPLY TheXml.nodes('/xml/generalData') AS A(g)
CROSS APPLY(SELECT g.value('(id/text())[1]', 'INT') AS GeneralDataID 
                 , g.value('(text/text())[1]', 'VARCHAR(30)') AS GeneralDataText) B
OUTER APPLY A.g.nodes('subElement') C(se)
OUTER APPLY TheXml.nodes('/xml/specialData[id=sql:column("B.GeneralDataID")]') AS D(sp);


来源:https://stackoverflow.com/questions/60527029/sql-server-xml-querying-query-multiple-child-elements-with-same-name

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!