In case of table that keeps the text, node ID and parent node ID, and does not have a row for root node, check this variation too:
drop table if exists Tree
create table Tree
(
id int NOT NULL PRIMARY KEY,
parent_id int REFERENCES Tree(id),
[text] nvarchar(max) NOT NULL
)
declare @xml as xml = '<?xml version="1.0" encoding="us-ascii" ?>
<TreeView>
<node text="Asia">
<node text="China">
<node text="Beijing"/>
</node>
<node text="Pakistan"/>
<node text="India"/>
<node text="Sri Lanka"/>
</node>
<node text="Europe">
<node text="Germany"/>
</node>
<node text="America"/>
<node text="Africa"/>
</TreeView>
'
;
with Q1 as
(
select
n.query('.') as x,
cast(NULL as nvarchar(max)) as txt,
cast(0x as varbinary(max)) as p
from @xml.nodes('/') n(n)
union all
select
n.query('.'),
v.txt,
p + cast(cast((ROW_NUMBER() over (order by v.txt)) as int) as varbinary(max))
from Q1
cross apply x.nodes('*/node') n(n)
cross apply (values (n.value('@text', 'nvarchar(max)'))) as v(txt)
),
Q2 as
(
select txt, p, ROW_NUMBER() over(order by len(p), p) as id
from Q1
where p <> 0x
),
Q3 as
(
select Q2.id, a.id as parent_id, Q2.txt
from Q2
left join Q2 as a on a.p = substring(Q2.p, 1, len(Q2.p)-4)
)
insert into Tree
select * from Q3
select * from Tree order by 1
The output:
id parent_id text
1 NULL Africa
2 NULL America
3 NULL Asia
4 NULL Europe
5 3 China
6 3 India
7 3 Pakistan
8 3 Sri Lanka
9 4 Germany
10 5 Beijing