我有两张表如下
表Person
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 Root的SQL。任何人都可以建议任何可以帮助我完成此任务的SQL
答案 0 :(得分:24)
您可以使用recursive CTE来实现这一目标:
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
<强> SQLFiddle DEMO 强>
编辑 - 针对所有孩子的最高级别父母的更新请求:
;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 r.ChildId, pc.Name AS ChildName, r.ParentId, pp.Name AS ParentName
FROM CTE_RN r
INNER JOIN dbo.Person pp ON pp.id = r.ParentId
INNER JOIN dbo.Person pc ON pc.id = r.ChildId
WHERE RN =1
<强> SQLFiddle DEMO 强>
EDIT2 - 让所有人在最后更改JOINS:
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
答案 1 :(得分:6)
我使用此模式将层次结构中的项目与项目的根节点相关联。 基本上递归层次结构,维护根节点的值作为附加到每一行的附加列。希望这会有所帮助。
with allRows as (
select ItemId, ItemName, ItemId [RootId],ItemName [RootName]
from parentChildTable
where ParentItemId is null
union all
select a1.ItemId,a1.ItemName,a2.[RootId],a2.[RootName]
from parentChildTable a1
join allRows a2 on a2.ItemId = a1.ParentItemId
)
select * from allRows
答案 2 :(得分:3)
要查找所有顶级父级,请使用以下查询:
select p.Name
from Person p
where not exists
(select null
from RelationHierarchy r
where r.ChildId = p.Id)
SQLFiddle here。
要查找特定孩子的顶级父级,请使用:
with cte as
(select t.ParentId TopParent, t.ChildId
from RelationHierarchy t
left join RelationHierarchy p on p.ChildId = t.ParentId
where p.ChildId is null
union all
select t.TopParent TopParent, c.ChildId
from cte t
join RelationHierarchy c on t.ChildId = c.ParentId)
select p.name
from cte h
join Person p on h.TopParent = p.Id
where h.ChildId=3 /*or whichever child is required*/
SQLFiddle here。
答案 3 :(得分:3)
试试这个。
递归CTE将找到该人并走向层次结构,直到找不到父级。
-- This CTE will find the ancestors along with a measure of how far up
-- the hierarchy each ancestor is from the selected person.
with ancestor as (
select ParentId as AncestorId, 0 as distance
from RelationHierarchy
where CHildId = ?
union all
select h.ParentId, a.distance + 1
from ancestor a inner join RelationHierarchy rh on a.AncestorId = rh.ChildId
)
select AncestorId
from ancestor
where distance = (select max(distance) from ancestor)
答案 4 :(得分:2)
这样的东西适用于上面的例子:
SELECT ParentId FROM RelationHierarchy
WHERE ParentId NOT IN (SELECT CHildId FROM RelationHierarchy)
答案 5 :(得分:1)
在“标准”SQL中执行此操作的唯一方法是假设树的最大深度,然后为每个级别执行连接。以下内容获得顶级ID:
select rh1.ChildId,
coalesce(rh4.parentid, rh3.parentid, rh2.parentid, rh1.parentid) as topLevel
from RelationshipHierarchy rh1 left outer join
RelationshipHierarchy rh2
on rh1.parentId = rh2.childId left outer join
RelationshipHierarchy rh3
on rh2.parentId = rh3.childId left outer join
RelationshipHierarchy rh4
on rh3.parentId = rh4.childId;
如果您想要名称,可以加入:
select rh1.ChildId,
coalesce(rh4.parentid, rh3.parentid, rh2.parentid, rh1.parentid) as topLevel,
p.name
from RelationshipHierarchy rh1 left outer join
RelationshipHierarchy rh2
on rh1.parentId = rh2.childId left outer join
RelationshipHierarchy rh3
on rh2.parentId = rh3.childId left outer join
RelationshipHierarchy rh4
on rh3.parentId = rh4.childId left outer join
Person p
on p.id = coalesce(rh4.parentid, rh3.parentid, rh2.parentid, rh1.parentid);
答案 6 :(得分:1)
使用路径获取所有顶级父母
路径格式:rootId /.../ parentId / nodeId /
select t1.path from nodes t1 inner join nodes t2
on t1.path like t2.path+'%'
group by t1.path
having len(t1.path)-len(replace(t1.path, '/', ''))
=min(len(t2.path)-len(replace(t2.path, '/', '')))
答案 7 :(得分:0)
放手一搏:
select id,name from person p where not exists ( select 1 from relationhierarchy r where r.childid= p.id ) and exists ( select 1 from relationhierarchy r where r.parentid= p.id )
仅仅查看子ID是否存在是不够的,因为在您的示例中,E存在于person表中但不存在于relationshiphierarchy表中。
答案 8 :(得分:0)
WITH CTE_MyTable AS (
SELECT Id, ParentId, NULL As RootParent, 1 As Lvl
FROM dbo.Ministry
UNION ALL
SELECT a.id, b.ParentId, a.ParentId As RootParent, Lvl + 1
FROM CTE_MyTableAS a INNER JOIN
dbo.MyTableAS b ON a.ParentId = b.Id
)
, CTE_Ministry_RN AS (
SELECT Id, RootParent, ROW_NUMBER() OVER (PARTITION BY Id ORDER BY Lvl DESC) RN
FROM CTE_Ministry
)
SELECT Id, ISNULL(RootParent, Id) As RootParent
FROM CTE_Ministry_RN
WHERE RN = 1