问题
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