我有以下两个表
表人
Id Name
1 A
2 B
3 C
4 D
5 E
表RelationHierarchy
ParentId CHildId
2 1
3 2
4 3
这将形成类似树的结构
D
|
C
|
B
|
A
ParentId和ChildId是Person Table
的Id列的外键我需要编写可以获取每个人的顶级父母i-e根的SQL。
以下CTE可以为每个人执行此操作。我将它转换为Function并为Person的每一行运行它。我在Person表中有大约3k行,这需要大约10秒。任何人都可以建议一种可以减少的方法。问题是CTE运行3k次后运行的函数
DECLARE @childID INT
SET @childID = 1 --chield to search
;WITH RCTE AS
(
SELECT *, 1 AS Lvl FROM RelationHierarchy
WHERE ChildID = @childID
UNION ALL
SELECT rh.*, Lvl+1 AS Lvl FROM dbo.RelationHierarchy rh
INNER JOIN RCTE rc ON rh.CHildId = rc.ParentId
)
SELECT TOP 1 id, Name
FROM RCTE r
inner JOIN dbo.Person p ON p.id = r.ParentId
ORDER BY lvl DESC
答案 0 :(得分:1)
我还更新了original question中的答案,但从不介意,这里也是副本:
;WITH RCTE AS
(
SELECT ParentId, ChildId, 1 AS Lvl FROM RelationHierarchy
UNION ALL
SELECT rh.ParentId, rc.ChildId, Lvl+1 AS Lvl
FROM dbo.RelationHierarchy rh
INNER JOIN RCTE rc ON rh.ChildId = rc.ParentId
)
,CTE_RN AS
(
SELECT *, ROW_NUMBER() OVER (PARTITION BY r.ChildID ORDER BY r.Lvl DESC) RN
FROM RCTE r
)
SELECT pc.Id AS ChildID, pc.Name AS ChildName, r.ParentId, pp.Name AS ParentName
FROM dbo.Person pc
LEFT JOIN CTE_RN r ON pc.id = r.CHildId AND RN =1
LEFT JOIN dbo.Person pp ON pp.id = r.ParentId
<强> SQLFiddle DEMO 强>
请注意,细微差别在于CTE的递归部分。现在每次从锚点部分重写ChildID。另外还有ROW_NUMBER()函数(以及新的CTE),以便最终获得每个孩子的最高级别。
编辑 - 版本2
在查找第一个查询的性能问题后,这是一个改进版本。从上到下,而不是其他方式 - 消除在CTE中创建额外的行,在大量递归时应该快得多:
;WITH RCTE AS
(
SELECT ParentId, CHildId, 1 AS Lvl FROM RelationHierarchy r1
WHERE NOT EXISTS (SELECT * FROM RelationHierarchy r2 WHERE r2.CHildId = r1.ParentId)
UNION ALL
SELECT rc.ParentId, rh.CHildId, Lvl+1 AS Lvl
FROM dbo.RelationHierarchy rh
INNER JOIN RCTE rc ON rc.CHildId = rh.ParentId
)
SELECT pc.Id AS ChildID, pc.Name AS ChildName, r.ParentId, pp.Name AS ParentName
FROM dbo.Person pc
LEFT JOIN RCTE r ON pc.id = r.CHildId
LEFT JOIN dbo.Person pp ON pp.id = r.ParentId
<强> SQLFiddle DEMO 强>
答案 1 :(得分:0)
您可以尝试使用循环。因为您将通过您的方法获得多级递归:
declare @child int = 0
declare @parent int = 1 --child to search
while @child <> @parent
BEGIN
set @child = @parent
select @parent = Parentid from @parentchild where ChildID = @child
END
select @parent
答案 2 :(得分:0)
如果你想使用集合,在循环中执行此操作的另一种方法是:
SELECT *
INTO #parentchild
from RelationHierarchy
WHILE EXISTS
(select 1 from #parentchild A inner join #parentchild B on A.ChildID = B.ParentID Where A.ParentID <> B.ParentID )
BEGIN
update B set B.ParentID = A.ParentID
from #parentchild A inner join #parentchild B on A.ChildID = B.ParentID
END
select * from #parentchild