获取家庭成员

问题描述 投票:7回答:4

假设家人在下面:

“家谱”

此构建模式为:

create table PersonConn (child int, parent int)
insert into PersonConn values (1,2)
insert into PersonConn values (1,3)
insert into PersonConn values (5,3)
insert into PersonConn values (5,4)
insert into PersonConn values (6,7)
insert into PersonConn values (6,8)
insert into PersonConn values (2,9)
insert into PersonConn values (2,10)
insert into PersonConn values (3,11)
insert into PersonConn values (3,12)

为了获得家庭成员的祖先,我可以使用以下所示的递归:

WITH Childs AS (
    SELECT distinct Child, Parent
    FROM  PersonConn
    WHERE Child = 1
    UNION ALL
    SELECT t2.Child, t2.Parent
    FROM   [Childs] t1
    INNER JOIN  PersonConn t2
        ON  t2.Child = t1.parent
)
SELECT PARENT FROM CHILDS

SQL Fiddle

将使用选定成员的所有祖先(在此示例中为ID 1),但不包括兄弟。该查询仅在家族树中上升。

我的[[问题是:

如何获得家庭的所有成员(儿子,父母,祖父,叔叔,堂兄等...)从一个人开始?

UPDATE

解决此问题的一种方法是在一个临时表中插入一个人的循环。之后,您可以将PersonConn表与此临时表连接并插入其他人。这样做直到没有人插入为止。我正在寻找一种更有效(更优雅)的方法。

我在PersonConn表中有大约200MM的记录。

sql sql-server sql-server-2012
4个回答
1
投票
我发现的解决方案根本不好。它给出了正确的答案,但即使对于这张很小的桌子也很慢。

1
投票
首先,我建议您在表中使用hierarchyid列。

0
投票
这在任何节点上都应该起作用。核心CTE仅在您从根子节点开始时才起作用。因此,如果开始的人不是一个孩子,那么第一部分将找到一个生子。该技术是沿着层次结构前进,然后下降,然后返回以使每个人都成为一个家庭。

0
投票
这里是Nizam 7月23日回答的简化版本。使用正确索引的DECLARE @PersonId INT = 10 -- if id passed in is not a root child, then get one If (SELECT Top 1 Parent FROM PersonConn WHERE Child = @PersonId) is null WITH CHILDS AS ( SELECT Child, 0 as [level] FROM PersonConn WHERE Parent = @PersonId UNION ALL SELECT t2.Child, [level] + 1 FROM CHILDS t1 INNER JOIN PersonConn t2 ON t2.Parent = t1.Child ) SELECT Top 1 @PersonId = Child FROM CHILDS ORDER BY [level] Desc; WITH CHILDS AS ( SELECT Child, Parent FROM PersonConn WHERE Child = @PersonId UNION ALL SELECT t2.Child, t2.Parent FROM CHILDS t1 INNER JOIN PersonConn t2 ON t2.Child = t1.parent ), PARENTS AS ( SELECT Child, Parent FROM PersonConn WHERE Parent in (Select parent from CHILDS) UNION ALL SELECT t2.Child, t2.Parent FROM PARENTS t1 INNER JOIN PersonConn t2 ON t2.parent = t1.child ), CHILDS2 AS ( SELECT Child, Parent FROM PersonConn WHERE Child in(Select child From Parents) UNION ALL SELECT t2.Child, t2.Parent FROM CHILDS2 t1 INNER JOIN PersonConn t2 ON t2.Child = t1.parent ) SELECT DISTINCT Parent, Child FROM CHILDS2 表,我得到了很好的结果(但是我无法用2亿条记录对其进行测试)。如果使用临时表代替表变量,则可以索引PersonConn,但我认为这样做不会提高性能,因为每次插入后都需要更新索引。
© www.soinside.com 2019 - 2024. All rights reserved.