简体   繁体   English

避免在SQL Server中进行while循环

[英]Avoiding while loop in SQL Server

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. 树的最大深度可能永远不会超过20个对象。 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. 有没有一种方法可以在没有while循环的情况下执行此操作...还是值得尝试避免针对此类/大小工作的while循环。

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" 上面的数据将导致路径“ Root \\ Middle1 \\ Middle2 \\ Leaf”

Recursive CTE is quite commonly used for this kind of tasks. 递归CTE非常常用于此类任务。 Below query will give a list of (ObjectId, Path) pairs for all rows in the dbo.tblObj : 下面的查询将为dbo.tblObj所有行提供(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

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

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM