Вы можете решить эту проблему - при условии, что на SQL Server 2005 или новее с рекурсивным CTE:
-- define a CTE (Common Table Expression) with a name
;WITH groups AS
(
-- define the "anchor" - those top-level rows
SELECT
GroupID, GroupName,
CAST(NULL AS INT) AS 'ParentGroupID', 1 AS 'Level',
CAST('# ' + GroupName AS VARCHAR(1000)) AS 'Breadcrumb'
FROM @test
WHERE ParentGroupID IS NULL
-- recursive join - joins "child" rows to "parent" rows already in the result set
UNION ALL
SELECT
t2.GroupID, t2.GroupName, t2.ParentGroupID, g.Level + 1 AS 'Level',
CAST(g.Breadcrumb + ' > ' + t2.GroupName AS VARCHAR(1000))
FROM @test t2
INNER JOIN groups g ON t2.ParentGroupID = g.GroupID -- join back to the CTE
)
SELECT *
FROM groups
Это должно дать вам результаты примерно так:
GroupID GroupName ParentGroupID Level Breadcrumb
1 group1 NULL 1 # group1
2 group2 NULL 1 # group2
3 subgroup1.1 1 2 # group1 > subgroup1.1
4 subgroup1.1.1 3 3 # group1 > subgroup1.1 > subgroup1.1.1
Любое дополнительное форматирование должно выполняться в вашем интерфейсе (веб, клиент / сервер).
Столбец Level
является дополнительным бонусом, сообщая вам, на каком уровне иерархии располагается каждая строка.