【问题标题】:How to follow parent_id through mysql table?如何通过mysql表跟踪parent_id?
【发布时间】:2013-01-27 12:21:34
【问题描述】:

我有一个代表伪目录系统的 mysql 表:

CREATE TABLE `file_directories` (
 `id` int(11) NOT NULL AUTO_INCREMENT,
 `parent_id` int(11) DEFAULT NULL,
 `name` varchar(255) NOT NULL,
 `level` int(11) NOT NULL DEFAULT '1',
 `created` datetime NOT NULL,
 PRIMARY KEY (`name`,`id`),
 KEY `id` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1

当用户浏览此系统时,我们的函数会收到一个由name 列中的条目组成的路径。

因此,first/child of first/grandchildsecond/child of second/grandchild 之类的内容将是有效路径,并且在数据库中看起来像这样。

/----------------------------------------------------\
| id | parent_id | name            | level | created |
|----|-----------|-----------------|-------|---------|
| 1  | NULL      | First           | 1     | ...     |
| 2  | 1         | Child of First  | 2     | ...     |
| 3  | 2         | Grandchild      | 3     | ...     |
| 4  | NULL      | Second          | 1     | ...     |
| 5  | 4         | Child of Second | 2     | ...     |
| 6  | 5         | Grandchild      | 3     | ...     |
\----------------------------------------------------/

现在,如果我想列出子目录,我的流程是这样的:

$path = 'first/child of first'; // demo data
$path = explode('/', $path); //array('first', 'child of first');
$level = count($path);
$name = end($path);

//query is not actually built like this, it uses the Codeigniter Active Records library
//but this is effectively the end result,
$sql = "SELECT * FROM `file_directories` WHERE `name` = '$name' AND `level` = $level";

///etc

这很好,直到我们处理 grandchild 目录,它们具有相同的名称并存在于同一级别。

目录结构强制只有一个目录可以存在相同的parent_idname,但相同的name'd 目录和不同的parent_id 可以存在于相同的level

我无法更改传递的数据,所以我能想到的唯一方法是从根节点开始,然后循环执行多个查询以找到正确的子节点。

因此,对于 second 的孙子,查询将是。

$parent_id = NULL;
foreach($path as $seg){
    $id = SQL: SELECT `id` FROM `file_directories` WHERE `name` = '$seg' AND `parent_id` = (IS NULL for root node) $parent_id;
}

//Get the actual node
$node = SQL: SELECT `*` FROM `file_directories` WHERE `id` = '$id';

但是,有很多查询,所以,在不改变我得到的数据的情况下,有没有更好的方法来跟踪树?还是选择正确的节点?

【问题讨论】:

  • 是否强制执行级别数?如果是这样,您可以使用父 ID 自行加入查询。

标签: php mysql recursion tree parent-child


【解决方案1】:

了解递归函数的神奇之处: 这段代码有点简化。

function select_child($node_id, $level, $target_level) {
  if(SELECT new_node_id WHERE parent_id = $node_id)
    if($level = $target_level) {
      return($new_node);
    } else {
      $results->add(select_child($new_node_id, ($level +1), $target_level);
    }
  } else {
    return(NULL);
  }
}

此函数循环遍历给定节点的子节点,直到找到“叶子”(没有子节点的节点)或达到目标级别。如果您正在使用树,您的大多数函数必须是递归的(调用它们自己直到匹配指定的条件)。

【讨论】:

  • 是的,这基本上就是我想要的,但我不喜欢做这么多的查询,这让我很恼火,我想我可以把整个结构从数据库中拉下来,并在数组中使用它,但这可能会变得巨大......
  • 正确。别担心。 SELECT 查询非常快。如果你再次使用相同的数据,很可能数据库已经缓存了这些数据。 (例如,将数据表的这一部分存储在 RAM 中),因此性能几乎与从数组中读取相同......如果您遇到性能问题,您有两个选择:在问题处抛出一些硬件 :) 或缓存结果第二个表中的递归函数。 (对于小型应用程序没有任何意义。)
  • 要加快数据库速度,您还可以在两个列上设置新索引。这将性能提高了 10-15 倍:D
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多