This is basically a recursive CTE. The tricky part is removing the current name from the family
list.
The following approach uses the recursive CTE to generate all family members and then returns the current name. If the names can overlap significantly (such as "grandchild1" and "child1"), then it might need to be tweaked. But it works for your example:
with cte as (
select id, name, convert(varchar(max), ',' + name) as family, 1 as lev
from t
where parent is null
union all
select t.id, t.name, concat(cte.family, ',', t.name), lev + 1
from cte join
t
on t.parent = cte.id
)
select id, name,
stuff(nullif(replace(family, ',' + name, ''), ''), 1, 1, '') as familh
from (select cte.*, max(lev) over (partition by id) as max_lev
from cte
) cte
where lev = max_lev;
Here is a little db<>fiddle.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…