据我了解,如果将一个零件定义为父零件而将另一个零件定义为子零件,那么多对多关系就是一个层次结构。
在某些情况下,我需要在多对多表中获取映射到自身的对象的子对象,但是我很难为其编写递归CTE。
例如,假设我有:
ParentId ChildId
======== =======
2 20
2 30
5 50
20 200
21 201
30 300
31 301
对于根级别,我使用的规则是,如果它的ID不在第二列(ChildId)中,则它是一个根对象,但这是有问题的,因为如上例所示,根的多个记录(ID:2)
对于递归部分,无论我尝试了什么,我要么获得了无限递归,要么递归根本不起作用。
所以我完全被困住了。
更新 只需添加更多说明即可。我正在构建一个存储过程,该存储过程在parentId中传递,并且内部具有递归CTE。我想要获得的输出是,使用上面的示例,通过2的parentId传递,我想要:
ParentId ChildId Level
======== ======= =====
2 20 0
2 30 0
20 200 1
30 300 1
这是我的一些代码:
alter procedure [dbo].[FindChildren]
@Id bigint
as
begin
;with DocumentHierarchyCTE (ParentId, ChildId, LevelNumber)
as
(
select
th.ParentDocumentId as ParentId,
th.ChildDocumentId as ChildId,
0 as LevelNumber
from dbo.DocumentHierarchy th
where
th.ParentDocumentId = @Id
and not exists(select 1 from dbo.DocumentHierarchy tz where tz.ChildDocumentId = th.ParentDocumentId )
union all
???
)
select *
from DocumentHierarchyCTE d
option (maxrecursion 0)
end
go
答案 0 :(得分:0)
这只是一个典型的递归cte,到处都有成千上万个示例。这将返回我认为您想要的。
declare @Something table
(
ParentId int
, ChildId int
)
insert @Something values
(2, 20)
, (2, 30)
, (5, 50)
, (20, 200)
, (21, 201)
, (30, 300)
, (31, 301)
declare @ParentID int = 2
;
with MyCTE as
(
select *, MyLevel = 0
from @Something s
where s.ParentId = @ParentID
AND ParentID not in
(
Select s2.ChildId
from @Something s2
)
union all
select s3.*, c.MyLevel + 1
from @Something s3
join MyCTE c on c.ChildId = s3.ParentId
)
select *
from MyCTE
答案 1 :(得分:0)
这里的答案基本上与肖恩·兰格相同。但是由于我已经准备好了,所以我还是想将其发布。
;WITH list_structure AS
(
SELECT
l.parentID,
l.childID,
0 AS levels
FROM list_hierarchy l
WHERE l.parentID NOT IN (SELECT childID FROM list_hierarchy)
UNION ALL
SELECT
l.parentID,
l.childID,
levels+1
FROM list_hierarchy l
INNER JOIN list_structure
ON l.parentID = list_structure.childID
)
SELECT * FROM list_structure