建立树视图

时间:2010-01-18 17:30:23

标签: php mysql tree

我对这个问题感到有点困惑,我已经考虑了一段时间了。我的数据库中有一个表可以执行任务。通过在parent_id字段中保存主键,每个任务都可以拥有父任务。我对这些任务的联系深度没有限制。

+-----------+-------+-----+
| Field     | Type  | Key |
+-----------+-------+-----+
| id        | int   | PRI |
| parent_id | int   | MUL |
+-------------------+-----+

没有parent_id的任务是“项目”,并且可以通过共享父任务将所有任务分组到任务组中。我现在想用一个HTML选择框填充项目的所有后代。

Task 1
  -Task 1.1
  -Task 1.2
    -Task 1.2.1
    -Task 1.2.2
  -Task 1.3
Task 2

我该如何解决这个问题?我认为某种递归函数是有序的,但我似乎无法真正想出如何去做。

任何帮助都会得到很大的帮助。 :)

3 个答案:

答案 0 :(得分:6)

我强烈建议您阅读有关storing hierarchical data in a database的文章。这里讨论了两种算法,根据您的需要,其中任何一种算法都是合适的。

邻接列表模型

这就是你现在拥有的。树的每个节点都存储对其父级的引用,您可以通过选择树的每个级别并迭代节点来递归地确定节点的路径。这很容易实现,但缺点是要确定节点的特定路径,需要递归查询。如果您的树受到很多更改(即写入),这是一个很好的方法,因为动态查找每个节点可以很好地适应不断变化的树。如果它读得很重,那么你在递归中会有一些开销。

修改预订树遍历

我最喜欢的,这是一个非常简洁的算法。您可以存储对每个给定节点的“左”和“右”节点的引用,而不是存储对父级的引用(为了方便起见,您可以执行此操作)。可以在单个选择查询中确定节点的整个路径,或者相反,可以在节点的所有子节点中确定。该算法难以实现,但它对读取繁重的树具有性能优势。缺点是每次移动或添加节点时,都必须重新计算树的整个分支,因此它可能不适合写入大量数据集。

无论如何,希望这篇文章能给你一些想法。这是一个很好的。

答案 1 :(得分:1)

这是一个如何递归遍历数据库以设置HTML表单的示例。它是zombat所谓的“邻接列表模型”的实现。

它使用两个函数:一个只是为了获得“顶级”元素(项目);和一个递归,以获得给定元素的所有子元素。然后我用它来填充HTML表单。

<?php
/**
 * Fetches all the projects and returns them as an array.
 * "Projects" meaning: tasks without a parent.
 * @return array
 */
function getProjects() {
    $sql = "SELECT id FROM tree WHERE parentID IS NULL";
    $result = mysql_query($sql) or die(mysql_error());
    $results = array();
    while($row = mysql_fetch_assoc($result)) {
        $results[] = $row['id'];
    }
    return $results;
}

/**
 * Fetches all tasks belonging to a specific parent.
 * Adds HTML space entities to represent the depth of each item in the tree.
 * @param int $parent_id The ID of the parent.
 * @param array $data An array containing the dat, filled in by the function.
 * @param int $current_depth Indicates the current depth of the recursion.
 * @return void
 */
function getTasks($parent_id, &$data, $current_depth=1) {
    $sql = "SELECT id FROM tree WHERE parentID = {$parent_id}";
    $result = mysql_query($sql) or die(mysql_error());
    while($row = mysql_fetch_assoc($result)) {
        $data[] = str_repeat('&nbsp;', $current_depth) . '- ' . $row['id'];
        getTasks($row['id'], $data, $current_depth + 1);
    }
}


/*
 * Fetch all the data and set it up so it can be used in the HTML
 */
mysql_connect('localhost', 'usr', 'pwd');
mysql_select_db('test');

// Get all the projects, adding a "-" as the initial value of the box.
$projects = array_merge(array('-'), getProjects());

// Fetch the tasks.
// If no project has been selected, just show a "please select"
$tasks = array();
if(isset($_GET['project']) && $_GET['project'] != '-') {
    getTasks($_GET['project'], $tasks);
}
else {
    $tasks = array('Select a project');
}

mysql_close();
?>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
    <title>Tree Select Example</title>
    <meta http-equiv="content-type" content="text/html; charset=UTF-8">
</head>
<body>
    <form action="<?php echo $_SERVER['PHP_SELF']; ?>" method="get">
        <select name="project" onchange="this.parentNode.submit();">
            <?php
            foreach($projects as $_project) {
                $selected = ($_project == @$_GET['project']) ? ' selected' : '';
                echo "<option value=\"{$_project}\"{$selected}>{$_project}</option>";
            }
            ?>
        </select><br>
        <select name="tasks[]" multiple size="10">
            <?php
            foreach($tasks as $_task) {
                echo "<option value=\"{$_task}\">{$_task}</option>";
            }
            ?>
        </select><br>
        <input type="submit">
    </form>
    <pre><?php print_r($_GET); ?></pre>
</body>
</html>

答案 2 :(得分:0)

请让此功能与您的虚线 - 指示器进行树视图。我为选择框选项做了。

function display_children($parent, $level) { 

    // retrieve all children of $parent 
    $output = "";
    $result = mysql_query('SELECT * FROM treeview_items  WHERE parent_id="'.$parent.'";'); 
    while ($row = mysql_fetch_array($result)) { 
        echo "<option value='".$row['id']."'>".str_repeat('--',$level).$row['name']."</option>" ."<br>"; 
        display_children($row['id'], $level+1); 
    } 
}