订购MySQL结果以遵守目录中的父/子

时间:2011-10-19 14:02:05

标签: php mysql hierarchical-data tableofcontents

我有一个目录的表格如下:

  • ID
  • Parent_ID
  • Display_Order

因此,每一行都是章节标题,但章节内的章节中可以有章节。因此,上表允许我维持这些关系。

如果章节没有父级,即它不是任何其他章节的子章节,则Parent_ID为“空”。如果一个章节确实有父,那么它的Parent_ID被设置为父章节的ID。

由于章节中可以有多个子章节,因此这些子章节的顺序通过Display_Order列进行管理; 1是第一,等等。

任何人都可以建议一个简洁的SQL查询,它允许我选择整个表,并产生一个完成上述操作的结果吗?基本上,我正在寻找一个反映章节实际层次结构的结果集。下面是ASCII TOC!

Chapter
-- Chapter
---- Chapter
---- Chapter
---- Chapter
-- Chapter
---- Chapter
---- Chapter
Chapter
Chapter

1 个答案:

答案 0 :(得分:0)

你不能只用SQL查询(至少在MySQL中)。 SQL和PHP的方法之一如下:

SELECT id, IFNULL(parent_id, 0) AS parentid, chapter FROM toc ORDER BY parentid, display_order

然后你将这个行集读到一个数组$ a,如下所示:

while ($row = mysql_fetch_array($result)) {
    $a[$row['id']]['name'] = $row['chapter'];
    $a[$row['parentid']]['children'][] = $row['id'];
}

它将创建一个带有第一个索引0的虚构元素。

一个小的示例函数,用于打印给定级别的缩进(您可以使用带填充的CSS而不是或任何其他方法来生成缩进):

function printIndent($level = 0) {
    for ($j = 0; $j <= $level; $j++) echo '&nbsp';
}

然后创建一个输出树的递归函数printTree:

function printTree($key = 0, $level = 0) {
    if ($key > 0) {
         printIndent($level);
         echo $a[$key]['name'];
    }
    if (count($a[$key]['children'])
        foreach ($a[$key]['children'] as $child)
             printTree($child, $level + 1);
}

然后用:

调用一次
printTree();

就是这样。请注意我跳过了数组初始化,我没有运行这个示例代码,所以它可能有语法错误,但原理就是这个。

这种方法的缺点是,如果您拥有非常多的项目,那么首先将所有内容一次性读取到大型数组时,这将不是最有效的。但对于较少数量的物品,这是一个很好的解决方案。