2

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 Answer 1

3

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);
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.