2013-08-26 210 views
1

我有一張表,其中包含對象的標識符和父項的標識符。它用於保存呈現爲樹的數據對象。我想查詢該表以構建樹中對象的完整路徑。樹的最大深度可能永遠不會超過20個物體。有沒有辦法做到這一點沒有一個while循環...或者是值得試圖避免這種類型/工作量的while循環。在SQL Server中避免while循環

表看起來是這樣的:

 
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,路徑)在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,我不確定那個_second部分的性能(可能它對於單個對象來說做得太多了),所以我更新了答案並添加了替代方法。如果遇到性能問題,您可以嘗試替代方案。 –

0

一個簡單的方法來實現的結果是,通過使用:

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