2013-08-26 2 views
1

У меня есть таблица, которая содержит идентификаторы объектов и идентификаторов их родителей. Он используется для хранения объектов данных, представленных в виде дерева. Я хочу запросить таблицу для создания полного пути к объекту в дереве. Максимальная глубина дерева, вероятно, никогда не выйдет за пределы 20 объектов. Есть ли способ сделать это без цикла while ... или стоит попытаться избежать цикла while для этого типа/размера работы.Избегание цикла while в SQL Server

таблица выглядит следующим образом:

 
CREATE TABLE [dbo].[tblObj] 
(
    [ObjectId] [int] NOT NULL, 
    [ObjectName] [nvarchar](50) NOT NULL, 
    [ParentId] [int] NULL, 
) 

с данными, как этот

 
insert into tblObj (ObjectId, ObjectName) values (1, 'Root') 
insert into tblObj (ObjectId, ObjectName, ParentId) values (2, 'Middle1', 1) 
insert into tblObj (ObjectId, ObjectName, ParentId) values (3, 'Middle2', 2) 
insert into tblObj (ObjectId, ObjectName, ParentId) values (4, 'Leaf', 3) 

желаемого результата использовать объект/родительские отношения, чтобы создать строку с именами объектов, которые отражают полный путь. Приведенные выше данные приведут к пути «Root \ Middle1 \ Middle2 \ Leaf»

+0

Пример ожидаемых результатов? В любом случае, вам, вероятно, нужен рекурсивный CTE. –

ответ

1

Рекурсивный CTE довольно часто используется для такого рода задач. Ниже запрос будет дать список (ObjectId, Path) пар для всех строк в dbo.tblObj:

;WITH cte (ObjectId, ParentID, [ObjectName], Path) 
AS(
    SELECT [ObjectId], [ParentID], [ObjectName], cast([ObjectName] as nvarchar(max)) 
    FROM dbo.tblObj 
    WHERE [ParentID] is NULL 
    UNION ALL 
    SELECT t.[ObjectId], t.ParentID, t.[ObjectName], cte.Path + '\' + t.[ObjectName] 
    FROM cte 
     JOIN dbo.tblObj t ON t.ParentID = cte.[ObjectId] 
) 
select ObjectID, Path 
from cte 

В случае, если вам нужно получить путь конкретного объекта, вы можете сделать это, как:

declare @objId int 
set @objId = 4 

;WITH cte (ObjectId, ParentID, [ObjectName], Path) 
AS(
    -- here code is the same as above 
) 
select Path 
from cte 
where ObjectID = @objId 

или, в качестве альтернативы, как:

declare @objId int 
set @objId = 4 

;with PathSteps(ObjectId, ParentID, ObjectName, Level) 
as 
(
    select ObjectId, ParentID, ObjectName, 0 
    from dbo.tblObj 
    where ID = @id 
    union all 
    select t.ObjectId, t.ParentID, t.ObjectName, p.Level - 1 
    from dbo.tblObj t 
     join PathSteps p on p.ParentID = t.ID 
), 
Path(ObjectPath) as (
    select stuff(
     (select '\' + ObjectName 
     from PathSteps 
     order by Level 
     for xml path(''), type).value('text()[1]', 'nvarchar(max)'), 1, 1, '') 
) 
select ObjectPath 
from Path 
+0

Это делает - спасибо. И спасибо за предоставление второй части, которая находит путь к определенному объекту. Это именно то, что я должен сделать. – Ken

+0

@Ken, я не уверен в производительности этой _секундной части (возможно, это слишком много для одного объекта), поэтому я обновил ответ и добавил альтернативный подход. Если вы столкнулись с проблемой производительности, попробуйте альтернативу. –

0

простой способ достижения результата состоит в использовании:

DECLARE @var VARCHAR(MAX) = '' 
SELECT @var = CASE WHEN @var = '' THEN '' ELSE @var+'/' END + ObjectName 
FROM tblObj ORDER BY ObjectId 
PRINT @var 
Смежные вопросы