EDIT: With generated IDs
This solution relys on your XML being loaded into a variable @xml
of type XML. If you need help with this, just call ;-)
WITH MyCompanies AS
(
SELECT ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) AS CompID
,Comp.value('name[1]','varchar(max)') AS Comp_Name
,Comp.query('.') AS Comp_InnerXML
FROM @xml.nodes('/root/companies/company') AS A(Comp)
)
,TheAddresses AS
(
SELECT MyCompanies.*
,ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) AS AddrID
,Addr.value('street[1]','varchar(max)') AS Addr_Street
,Addr.query('.') AS Addr_InnerXML
FROM MyCompanies
OUTER APPLY Comp_InnerXML.nodes('company/addresses/address') AS A(Addr)
)
SELECT TheAddresses.*
,ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) AS ContID
,Cont.value('fullName[1]','varchar(max)') AS Cont_FullName
INTO #temp
FROM TheAddresses
OUTER APPLY Addr_InnerXML.nodes('address/contacts/contact') AS C(Cont);
SELECT * FROM #temp;
The result
+--------+-----------+--------+-----------------+--------+---------------+
| CompID | Comp_Name | AddrID | Addr_Street | ContID | Cont_FullName |
+--------+-----------+--------+-----------------+--------+---------------+
| 1 | XYZ Co. | 1 | 12 Light Street | 1 | NULL |
+--------+-----------+--------+-----------------+--------+---------------+
| 1 | XYZ Co. | 2 | 44 King Street | 2 | Bob |
+--------+-----------+--------+-----------------+--------+---------------+
| 1 | XYZ Co. | 2 | 44 King Street | 3 | Alice |
+--------+-----------+--------+-----------------+--------+---------------+
| 2 | ABC Co. | 3 | 12 ABC Street | 4 | NULL |
+--------+-----------+--------+-----------------+--------+---------------+
| 2 | ABC Co. | 4 | 44 ABC Street | 5 | Bob ABC |
+--------+-----------+--------+-----------------+--------+---------------+
| 2 | ABC Co. | 4 | 44 ABC Street | 6 | Alice ABC |
+--------+-----------+--------+-----------------+--------+---------------+
Within #temp you have the data. Use DISTINCT
to do your inserts from there...
--Your companies
SELECT DISTINCT CompID,Comp_Name FROM #temp;
--Your address
SELECT DISTINCT CompID,AddrID,Addr_Street FROM #temp;
--Your contacts
SELECT DISTINCT AddrID,ContID,Cont_FullName FROM #temp;
previous
This query will get the data into table data.
But: You should insert this into related tables (company,address,contacts) rather an all in one.
You can create dummy IDs using ROW_NUMBER
with OVER(PARTITION BY ...)
to generate dummy IDs but this will work only in the first run.
SELECT Comp.value('name[1]','varchar(max)') AS Comp_Name
,Addr.value('street[1]','varchar(max)') AS Addr_Street
,Cont.value('fullName[1]','varchar(max)') AS Cont_FullName
FROM @xml.nodes('/root/companies/company') AS A(Comp)
OUTER APPLY Comp.nodes('addresses/address') AS B(Addr)
OUTER APPLY Addr.nodes('contacts/contact') AS C(Cont)
The result
Comp_Name Addr_Street Cont_FullName
XYZ Co. 12 Light Street NULL
XYZ Co. 44 King Street Bob
XYZ Co. 44 King Street Alice
ABC Co. 12 ABC Street NULL
ABC Co. 44 ABC Street Bob ABC
ABC Co. 44 ABC Street Alice ABC