2

我觉得这一定是一个经典问题,但我找不到答案。

我有一张 Person 表,里面有描述一个人的基本细节。然后,我有一个 ParentChildRelationship 表,它看起来像这样:

CREATE TABLE `ParentChildRelationship` (
    `ParentId` INT(10) UNSIGNED NOT NULL,
    `ChildId` INT(10) UNSIGNED NOT NULL,
 PRIMARY KEY(ParentId,ChildId),
 CONSTRAINT `FK_ParentRelationship`
    FOREIGN KEY (`ParentId` )
    REFERENCES `Person` (`idPerson` ),
 CONSTRAINT `FK_ChildRelationship`
    FOREIGN KEY (`ChildId` )
    REFERENCES `Person` (`idPerson` )
);

我需要一个选择查询,它只返回树下的父级和所有子级的所有人员记录。

例如,使用以下数据:

Parent   Child
1        3
1        8
2        4
3        5
3        6
6        9
4        7

选择 ParentId = 1 OR ChildId 位于ParentId 为 1下方Person的树中的所有 Person 记录。此查询应返回以下 PersonId 的Person 信息 (SELECT * FROM ...):

1,3,8,5,6,9

我不知道这是否重要,但是这些返回的顺序并不重要,因为我需要根据“LastName”之类的东西来订购。换句话说,结果也可能是 1,3,5,6,9,8。

4

3 回答 3

3

如果您有一个已知的有限深度,您可以展开递归并使用存储过程或视图。对于 MySQL,以下工作:

存储例程解决方案:

DELIMITER $$ 

CREATE PROCEDURE GetRelatedPersonsWithPersonId( IN pId VARCHAR(36)) 
        BEGIN 
                select * from Person where idPerson in ( 
                        select ParentId from ParentChildRelationship where ParentId = pId 
                        union 
                        select ChildID from ParentChildRelationship where ParentId = pId 
                        union 
                        select ChildID from ParentChildRelationship where ParentId in (select ChildID from ParentChildRelationship where ParentId = pId) 
                        union 
                        select ChildID from ParentChildRelationship where ParentId in (select ChildID from ParentChildRelationship where ParentId in (select ChildID from ParentChildRelationship where ParentId = pId)) 
                ) ; 

        END $$ 

查看解决方案:

Create view ChildRecurse 
As 
Select ParentId, ChildID from ParentChildRelationship 
Union 
Select x1.ParentId, x2.ChildId from ParentChildRelationship x1 
               Inner join ParentChildRelationship x2 on x2.ParentId = x1.ChildId 
Union 
Select x1.ParentId, x3.ChildId from ParentChildRelationship x1 
               Inner join ParentChildRelationship x2 on x2.ParentId = x1.ChildId 
               Inner join ParentChildRelationship x3 on x3.ParentId = x2.ChildId 
Union 
Select x1.ParentId, x4.ChildId from ParentChildRelationship x1 
               Inner join ParentChildRelationship x2 on x2.ParentId = x1.ChildId 
               Inner join ParentChildRelationship x3 on x3.ParentId = x2.ChildId 
               Inner join ParentChildRelationship x4 on x4.ParentId = x3.ChildId 

然后像这样选择:

select * from person where idPerson=@ID or idPerson in (select ChildId from ChildRecurse where ParentId=@ID) 
于 2012-10-26T19:12:50.653 回答
1

您的数据模型称为邻接表模型。您无法使用该模型执行您描述的查询(尽管存储过程可以)。

解决此问题的常用方法是更改​​为嵌套集模型。Wikipedia 文章有一些示例代码,并且这里有一个很好的教程以及对使用邻接列表模型所涉及的内容的很好描述)。

于 2012-10-26T05:36:59.093 回答
0

我认为这将是 GROUP BY 和 HAVING 语句的工作。

这样的事情是否会为您指明正确的方向?

SELECT * FROM ParentChildRelationship pcr
GROUP BY ParentID , ChildID
HAVING ParentID=1 OR Count(ChildID)>0 

这将为您提供一个父子关系列表,您可以使用 INNER JOIN 将其加入到persons 表中。

于 2012-10-26T05:40:29.683 回答