在mysql中停止递归乱伦的子父关系

时间:2012-07-25 14:47:23

标签: php mysql recursion parent

我用PHP / MySQL / Javascript编程。 我有一个我们想要在子/父关系中链接的部分列表,对层数没有限制。

当我从部件列表中选择要将子项添加到父级时,我限制了部件列表以排除父本身以及已经是该父级子项的任何部分。

我发现我也想排除父母的祖父母,否则我们就会得到一种乱伦的关系,当我展示部分树时会产生无限循环。

不仅如此,我不能让孩子成为父母或曾祖父母的伟大祖父母。

这是我目前使用的SQL语句,我认为也可以使用LEFT JOIN进行改进,但此时我对SQL技术不够熟练。

SELECT * 
FROM sch_part_general 
WHERE (sch_part_general.part_id <> $parentId) 
AND (sch_part_general.part_id NOT IN 
  (SELECT part_id FROM sch_part_mapping WHERE parent_id = $parentId)
)

sch_part_general是一个包含所有部分的多列表,其中part_id为主键。 sch_part_mapping是一个带有part_id(child)||的双列映射表parent_id(parent)。

有人能用SQL查询指出我正确的方向吗?我并不热衷于使用while循环来创建SQL语句,因为我认为这将是非常低效的,但它是我认为可能工作的唯一方法。

3 个答案:

答案 0 :(得分:6)

MySQL对分层查询没有太多(如果有)支持。如果你想坚持所谓的Adjacency List Model,你所能做的就是为你想要包含的每个级别添加JOIN。不用说,这不能很好地扩展。

另一方面,如果您可以更改数据库架构,我建议您实施Nested Set Model

Nested Set Model

中提供了{{1}}的一个非常好的解释
  

邻接列表模型的限制

     

在纯SQL中使用邻接列表模型可能很困难   最好。在能够看到我们必须的类别的完整路径之前   知道它所在的水平。

     

嵌套集模型

     

SQL中嵌套集的概念已经存在了十多年,   书中还有很多其他信息   互联网。在我看来,最全面的来源   有关管理分层信息的信息是一本名为Joe的书   Celko的Tree and Hierarchies in SQL for Smarties,由一个非常好的   尊敬的高级SQL领域的作者Joe Celko。

答案 1 :(得分:1)

如果你不能改变架构,那么就像Lieven的答案所暗示的那样,没有逃避循环。

如果您可以更改架构,那么以下内容对您的案例也可能就足够了: 在sch_part_mapping中添加一个新列,我们称之为“hierarchy_id”。它是一个值,在你第一次启动一个全新的层次结构时构造成唯一的int(在任何层次结构中有第一个盛大的最盛大的最大父级 - 但是用英语表示)并插入到属于单个层次结构的所有行中什么级别的问题。

然后,它很容易跳过在同一层次结构中找到的父母和祖父:到你上面的sql然后你可以添加:

SELECT * 
FROM sch_part_general 
WHERE (sch_part_general.part_id <> $parentId) 
AND (sch_part_general.part_id NOT IN 
  (SELECT part_id FROM sch_part_mapping WHERE parent_id = $parentId)

//addition here 
and not exists (select * from sch_part_mapping where hierarchy_id= ? and parent_id = sch_part_general.part_id)

)

问号应替换为您需要计算的相关层数。

编辑:我错过了您有特定父ID的变量,因此hierarchy_id可以在同一查询中计算:

SELECT * 
    FROM sch_part_general 
    WHERE (sch_part_general.part_id <> $parentId) 
    AND (sch_part_general.part_id NOT IN 
      (SELECT part_id FROM sch_part_mapping WHERE parent_id = $parentId)

    //addition here 
    and not exists (select * from sch_part_mapping where hierarchy_id= (select hierarchy_id from sch_part_mapping where parent_id = $parentId limit 1) and parent_id = sch_part_general.part_id)


)

答案 2 :(得分:0)

使用MySql / MariaDB,您可以使用Open Query Graph引擎(http://openquery.com/graph/doc),这是一个mysql插件,可以让您创建一个特殊的表来放置关系,基本上是parentId和childId。

神奇的是,您使用特殊列锁存器查询此表,具体取决于查询中传递的值将告诉OQGRAPH引擎执行哪个命令。有关详细信息,请参阅文档。

它不仅处理树(递归1-n关系),而且处理图形数据结构(递归nm关系)与权重(例如,想要存储公司所有权,公司可以有几个子公司,也可以有几个股东)。