如何对SELECT语句的记录进行排序,使它们代表一个有效的树?
我的所有尝试都显示子节点嵌套在错误的父节点下。实现这种排序的最可靠方法是什么?
数据
ID Parent ID Title
--------------------------------------------
0 NULL Root
1 0 Node A
2 0 Node B
3 1 Sub-Node C
4 1 Sub-Node D
5 3 Sub-Node E
输出
ID Parent ID Title
--------------------------------------------
0 NULL Root
1 0 Node A
3 1 Sub-Node C
5 3 Sub-Node E
4 1 Sub-Node D
2 0 Node B
数据可视化
Root
Node A
Sub-Node C
Sub-Node E
Sub-Node D
Node B
答案 0 :(得分:13)
您可以使用嵌套集。看看这篇文章:
Managing Hierarchical Data in MySQL
作者描述了在SQL中构建层次结构的几种不同方法,以及示例查询。关于这个主题,这是一个很好的阅读!
答案 1 :(得分:5)
根据@Blindy的建议,我已经用PHP实现了这种方式。以下两个函数似乎相对容易解决了这个问题。
protected function _sort_helper(&$input, &$output, $parent_id) {
foreach ($input as $key => $item)
if ($item->parent_id == $parent_id) {
$output[] = $item;
unset($input[$key]);
// Sort nested!!
$this->_sort_helper(&$input, &$output, $item->id);
}
}
protected function sort_items_into_tree($items) {
$tree = array();
$this->_sort_helper(&$items, &$tree, null);
return $tree;
}
我很想知道是否有更简单的方法,但这确实有用。
答案 2 :(得分:4)
MySQL不支持递归查询
您需要自动加入表格,因为最大层次结构级别是多次,但是以这种方式为每个层次结构级别获取一行仍然非常难看。
请参阅这些帖子以获取一些想法和示例:
答案 3 :(得分:0)
我刚刚完成了这个递归函数,并认为这是一个关于问题的优雅方式。这是我做了一个基本的SELECT mysql查询后所做的事情:
function orderChildren($data){
$tree = array();
foreach($data as $value){
if($value['parent_id'] == null){ // Values without parents
$tree[$value['id']] = $this->goodParenting($value, $data);
}
}
return $tree;
}
private function goodParenting($parent, $childPool){
foreach($childPool as $child){
if($parent['id'] == $child['parent_id']){
$parent['children'][$child['id']] = $this->goodParenting($child, $childPool);
}
}
return $parent;
}
答案 4 :(得分:0)
这是另一种执行PHP功能的方法。
function buildTree() {
$data = array();
$pointers = array();
$sql = "SELECT ID,PARENT,TITLE FROM TREE ORDER BY TITLE ASC";
$res = $this->db->query($sql);
while ($row = $res->fetch(PDO::FETCH_ASSOC)) {
if(!isset($pointers[$row['ID']])) {
$pointers[$row['ID']] = $row;
}
if(!empty($row['PARENT'])) {
if(!isset($pointers[$row['PARENT']])) {
$pointers[$row['PARENT']] = $row;
}
$pointers[$row['PARENT']][$row['ID']] = &$pointers[$row['ID']];
} else {
$data[$row['ID']] = &$pointers[$row['ID']]; // This is our top level
}
}
unset($pointers);
return $data;
}