在SQL Server中避免while循环

时间:2013-08-26 16:04:46

标签: sql sql-server while-loop

我有一个表,其中包含对象的标识符和父项的标识符。它用于保存呈现为树的数据对象。我想查询表以构建树中对象的完整路径。树的最大深度可能永远不会超过20个对象。有没有办法在没有while循环的情况下执行此操作...或者是否值得尝试避免此类型/大小工作的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”

2 个答案:

答案 0 :(得分:1)

递归CTE非常常用于此类任务。下面的查询将给出dbo.tblObj中所有行的(ObjectId,Path)对列表:

;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

答案 1 :(得分:0)

实现结果的简单方法是使用:

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