2

I have a table that holds identifiers of objects and identifiers of their parents. It is used to hold the data objects that are presented as a tree. I want to query the table to build a full path to an object in the tree. The tree's max depth will probably never go beyond 20 objects. Is there a way to do this without a while loop...or is it worth trying to avoid a while loop for this type/size of work.

The table looks like this:

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

with data like this

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)

The desired result is to use the object/parent relationships to build a string with the object names that reflect the full path. The data above would result in the path "Root\Middle1\Middle2\Leaf"

1
  • Example of expected results? You probably need a recursive CTE anyway. Commented Aug 26, 2013 at 16:24

2 Answers 2

2

Recursive CTE is quite commonly used for this kind of tasks. Below query will give a list of (ObjectId, Path) pairs for all rows in the 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

In case if you need to obtain path of a particular object, you can do it as:

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

or, alternatively, as:

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
Sign up to request clarification or add additional context in comments.

2 Comments

That does it - thanks. And thanks for providing the second portion that finds the path of a particular object. That's exactly what I have to do.
@Ken, I'm not sure about performance of that second portion (may be it is doing too much for just single object), so I updated answer and added alternative approach. If you run into performance issue, you may try alternative.
0

A simple way to achieve the result is by using:

DECLARE @var VARCHAR(MAX) = ''
SELECT @var = CASE WHEN @var = '' THEN '' ELSE @var+'/' END + ObjectName 
FROM tblObj ORDER BY ObjectId
PRINT @var

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.