避免 SQL Server 中的 while 循环
Posted
技术标签:
【中文标题】避免 SQL Server 中的 while 循环【英文标题】:Avoiding while loop in SQL Server 【发布时间】:2013-08-29 04:31:12 【问题描述】:我有一个表,其中包含对象的标识符及其父对象的标识符。它用于保存以树的形式呈现的数据对象。我想查询表以构建树中对象的完整路径。树的最大深度可能永远不会超过 20 个对象。有没有办法在没有while循环的情况下做到这一点......或者是否值得尝试避免这种类型/大小的工作的while循环。
表格如下所示:
创建表 [dbo].[tblObj] ( [ObjectId] [int] 非空, [对象名] [nvarchar](50) 非空, [ParentId] [int] NULL, )这样的数据
插入 tblObj (ObjectId, ObjectName) 值 (1, 'Root') 插入 tblObj (ObjectId, ObjectName, ParentId) 值 (2, 'Middle1', 1) 插入 tblObj (ObjectId, ObjectName, ParentId) 值 (3, 'Middle2', 2) 插入 tblObj (ObjectId, ObjectName, ParentId) 值 (4, 'Leaf', 3)期望的结果是使用对象/父关系来构建一个包含反映完整路径的对象名称的字符串。上面的数据会导致路径“Root\Middle1\Middle2\Leaf”
【问题讨论】:
预期结果示例?无论如何,您可能需要递归 CTE。 【参考方案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
【讨论】:
就是这样 - 谢谢。并感谢提供找到特定对象路径的第二部分。这正是我必须做的。 @Ken,我不确定 第二部分 的性能(可能是它对单个对象做的太多),所以我更新了答案并添加了替代方案方法。如果您遇到性能问题,您可以尝试其他方法。【参考方案2】:实现结果的一种简单方法是使用:
DECLARE @var VARCHAR(MAX) = ''
SELECT @var = CASE WHEN @var = '' THEN '' ELSE @var+'/' END + ObjectName
FROM tblObj ORDER BY ObjectId
PRINT @var
【讨论】:
以上是关于避免 SQL Server 中的 while 循环的主要内容,如果未能解决你的问题,请参考以下文章
SQL Server 基于集合的 while 循环避免万圣节保护 (LAHP) 用于层次结构透视将某些结果减半