这是一个使用 while 循环的答案。
解决方案 1,使用 while 循环和临时表
/* Populating the temp table with the data */
DECLARE @recurse TABLE
(projectId INT,parent int);
INSERT INTO @recurse (projectId,parent) VALUES (1,-1);
INSERT INTO @recurse (projectId,parent) VALUES (2,-0);
INSERT INTO @recurse (projectId,parent) VALUES (3,2);
INSERT INTO @recurse (projectId,parent) VALUES (4,2);
INSERT INTO @recurse (projectId,parent) VALUES (5,-1);
INSERT INTO @recurse (projectId,parent) VALUES (6,3);
INSERT INTO @recurse (projectId,parent) VALUES (7,6);
DECLARE @recurse2 TABLE
(projectId INT,parent INT);
--Start by inserting the root element
INSERT INTO @recurse2 ( projectId, parent)
SELECT * FROM @recurse WHERE projectId = 2
--insert elements until all children have all children
WHILE EXISTS (SELECT * FROM @recurse WHERE parent IN (SELECT projectId FROM @recurse2) AND projectId NOT IN (SELECT projectId FROM @recurse2) )
BEGIN
INSERT INTO @recurse2
(
projectId,
parent
)
SELECT * FROM @recurse WHERE parent IN (SELECT projectId FROM @recurse2) AND projectId NOT IN (SELECT projectId FROM @recurse2)
END
SELECT * FROM @recurse2
解决方案 2
为了提高性能,您可以使用 while 循环的结果创建一个中间表。此中间表可以按时间间隔更新,或者作为在主表中创建元素的一部分。这可能是您业务逻辑的一部分,也可能是数据库触发器。
如果您希望将此作为计划作业,这是我将编写的代码:
-- Populating the temp table with the data
DECLARE @recurse TABLE
(projectId INT,parent int);
INSERT INTO @recurse (projectId,parent) VALUES (1,-1);
INSERT INTO @recurse (projectId,parent) VALUES (2,-0);
INSERT INTO @recurse (projectId,parent) VALUES (3,2);
INSERT INTO @recurse (projectId,parent) VALUES (4,2);
INSERT INTO @recurse (projectId,parent) VALUES (5,-1);
INSERT INTO @recurse (projectId,parent) VALUES (6,3);
INSERT INTO @recurse (projectId,parent) VALUES (7,6);
DECLARE @recurse2 TABLE
(projectId INT,parent INT, lvl int);
--Start by inserting all elements root at lvl 0
INSERT INTO @recurse2 ( projectId, parent, lvl ) SELECT projectId, parent, 0 FROM @recurse
SELECT * FROM @recurse2
--insert elements until we have all parents for all elements
WHILE EXISTS (SELECT * FROM @recurse2 a WHERE lvl IN (SELECT TOP 1 lvl FROM @recurse2 b WHERE a.projectId = b.projectId ORDER BY lvl DESC) AND a.parent > 0 )
BEGIN
--Insert the next parent for all elements that does not have a their top level parent allready
INSERT INTO @recurse2 ( projectId, parent , lvl )
SELECT projectId,
(SELECT b.parent FROM @recurse b WHERE b.projectId = a.parent),
lvl + 1
FROM @recurse2 a WHERE lvl IN (SELECT TOP 1 lvl FROM @recurse2 b WHERE a.projectId = b.projectId ORDER BY lvl DESC) AND a.parent > 0
END
--Find all children to an element
SELECT * FROM @recurse2 WHERE parent = 2
解决方案#2 的最大优势是性能应该非常适合读取,甚至可能比 CTE 更好。它同样适用于从下到上阅读,就像从上到下一样。