2016-09-27 36 views
0

我试图让我的头在PHP/MySQL特别是Codeigniter中使用封闭表,我正在建设的应用程序有区域,每个区域可以有一些地点,部门等插入与PHP/MySQL的封闭表

我一直在使用http://www.slideshare.net/billkarwin/models-for-hierarchical-data了解它是如何工作的。

而且我也一直在使用https://gist.github.com/dazld/2174233来帮助我掌握访问数据的方法,我可以做的很好,我已经调整了方法来根据需要提取数据,这很好。

但现在我试图插入数据,我不能得到我的头。所以我改编自上面的脚本add方法,但我不明白,我不能让它的工作

继承人的范围表

+------------+-------------+------+-----+---------+----------------+ 
| Field  | Type  | Null | Key | Default | Extra   | 
+------------+-------------+------+-----+---------+----------------+ 
| area_id | int(11)  | NO | PRI | NULL | auto_increment | 
| area_title | varchar(40) | NO |  | NULL |    | 
| area_name | varchar(40) | NO |  | NULL |    | 
| org_id  | int(11)  | NO |  | NULL |    | 
+------------+-------------+------+-----+---------+----------------+ 

继承人的area_hierarchy表

+------------+---------+------+-----+---------+----------------+ 
| Field  | Type | Null | Key | Default | Extra   | 
+------------+---------+------+-----+---------+----------------+ 
| id   | int(11) | NO | PRI | NULL | auto_increment | 
| ancestor | int(11) | NO |  | NULL |    | 
| descendant | int(11) | NO |  | NULL |    | 
| lvl  | int(11) | NO |  | NULL |    | 
+------------+---------+------+-----+---------+----------------+ 

继承人的方法,我试图用添加条目:

public function add($node_id, $target_id) { 

    $sql = 'SELECT ancestor, '.$node_id.', lvl+1 
      FROM area_hierarchy 
      WHERE descendant = '.$target_id.' 
      UNION 
      SELECT '.$node_id.','.$node_id.',0'; 

    $query = 'INSERT INTO area_hierarchy (ancestor, descendant,lvl) ('.$sql.')'; 

    $result = $this->db->query($query); 

    return $result; 

} 

那么具体的,什么是$ node_id和$ target_id。

什么是lvl + 1?

所以,如果我添加一个新的顶级区域,我传递给这个方法的数据是什么?

查询也将失败,并给出UNION

+1

节点ID是您要添加的新节点(子),目标ID是父节点(祖先)。工会要处理自我引用,你应该始终关闭自我引用。如果我想在B下添加D,我需要选择B的所有祖先并创建与D的关系,我还需要根据D = D的级联为零创建自引用。 –

+1

在你的例子中,假设你有10个区域,1,2,3,4,5,它们有完全相同的主键。它们应该都存在于根级别上,你可以首先添加这些区域,然后你可以为每个节点调用'add($ areaId)'。然后你希望6,7,8成为3的孩子。然后你可以为每个区域调用'add($ areaId,3)'。最后,我们希望9和10是8的孩子。我们调用'add($ areaId,8)'。如果您需要关于为什么您的查询失败或未按预期工作的帮助,则需要向我们提供错误和预期结果。 –

+0

谢谢,很好的解释。我会离开和体验 – frobak

回答

1

$node_id后一个语法错误,就会从areaarea_id列的值。据推测,这是刚刚添加到区域表中的一行。

$target_id将作为area表中另一行的area_id列的值,该行是您标识为“父”的行,即直接祖先。

lvl+1是层次结构中的世代或层次......后代与其父代的“远”程度。

如果您要添加新的“顶级”区域,您可以使用$node_id代替$target_id

了解这一点的最佳方法之一是查看area_hierarchy表的“当前状态”以及添加节点时表的“结束状态”。

只需在树中的顶级节点,AREA_ID = 11,area_hierarchy表是这样的:

ancestor descendant lvl 
-------- ---------- --- 
11  11   0 

如果再加上另一行区域分配表,AREA_ID = 22,作为一个孩子AREA_ID = 11(嫡系),我们需要添加这两个行area_hierarchy:

ancestor descendant lvl 
-------- ---------- --- 
11  22   1 
22  22   0 

如果再加上另一行区表,AREA_ID = 333,作为AREA_ID = 22的孩子,我们需要将这些行添加到area_hierarchy表中:

ancestor descendant lvl 
-------- ---------- --- 
11  333  2 
22  333  1 
333  333  0 

请注意,我们需要添加的前两行看起来很像表中已存在的行,其中后代= 22。区别在于新行的后代是333而不是22,lvl的值比我们在表中已经有的行多一个。

我们需要添加的第三行是对自身的引用。就像我们将area_id = 11作为自己的“父母”一样。

我们从UNION之后的部分得到第三行。前两行是通过复制area_hierarchy中的行,将后代列的值替换为我们添加的节点的标识(333),并将lvl增加1.

一旦您了解了哪些行需要添加,以及我们如何通过复制/修改表中的其他行来派生它们,然后SQL开始有意义。


您将完成添加这三行的AREA_ID = 333,调用add函数:如果你想添加AREA_ID = 4444的层次结构中的一个新的 “顶级”

add(333,22); 

add(4444,4444); 
+0

感谢您的提问,非常翔实并且清楚。现在我还有另外一个问题了,我是否应该将列表索引到列表中,比如说组织的ID? – frobak

+0

@frobak:是的,添加适当的索引。索引有几个重要的目的。首先,索引可以用来强制执行唯一的约束。如果您希望数据库阻止将重复行添加到表中,您将添加一个唯一约束。考虑例如执行第二个调用'add(4444,4444)'。你想在数据库中结束什么状态?你想在area_hierarchy表中有两个*相同的行吗?索引的另一个目的是提高性能。哪些索引最适合取决于哪​​些语句将被执行。 – spencer7593