我正在创建一个带有parentid的类别的树结构,可以通过这种方式从孩子那里调用:
ID | Name | ParentID
1 1 0
2 2 1
3 3 2
4 4 1
导致:
1 = 1
2 = 1 -> 2
3 = 1 -> 2 -> 3
4 = 1 -> 4
表示 3是2 的孩子,是1的孩子。
当试图获得这个想法时(使用 - >来显示设置了什么关系)我只到达二年级(1 - > 2)但不到第三年级(1> 2-> 3)因为我使用的循环函数。
//put all ID's in an array
while ($row2 = $connector->fetchArray($result2)){
$id = $row2['ID'];
$parents[$id] = $row2['name'];
}
// show the tree-structure
while ($row = $connector->fetchArray($result)){
if($row['parentid']!=0)echo $parents[$row['parentid']].' -> ';
echo $row['name'].' - ';
echo '<br>';
}
我想要改变两件事:
- 让代码自动生成根据需要调整大小的树。
- 在while循环中我必须选择$ result两次(一次为$ result,一次为$ result2)以使其工作。这些$ result具有完全相同的数据库查询:
醇>
SELECT ID,name,parentid FROM categories
从中获取结果。我只想宣布一次。
感谢所有好的答案。我已经采用了最简单,代码更少的实现方法:
$result = $connector->query('SELECT ID,name,parentid FROM categories');
// Get an array containing the results.
$parents = array();
while ($row = $connector->fetchArray($result)){
$id = $row['ID'];
$parents[$id] = array('ID' => $row['ID'],'name' => $row['name'],'parentid' => $row['parentid']);
}
foreach ($parents as $id => $row){
$pid=$id;
$arrTmp= array();
do { // iterate through all parents until top is reached
$arrTmp[]=$pid;
$pid = $parents[$pid]['parentid'];
}while ($pid != 0);
$arrTmp = array_reverse($arrTmp);
foreach($arrTmp as $id){
echo $parents[$id]['name'].' -> ';
}
echo '<br>';
}
答案 0 :(得分:3)
为什么不让PHP将项目组织到树中呢?为什么不让数据库为你做呢?我发现这个article on hierarchical data非常好,并且示例几乎与您的相同。
修改强>
使用Adjacency Model获取完整树的SQL并不理想。正如文章解释的那样,即使是一个小的层次结构,它也需要很多连接。您是否不可能使用嵌套集方法?无论层次结构的大小如何,SQL都保持不变,INSERT和DELETE也不应该非常困难。
答案 1 :(得分:1)
如果您真的想要使用父ID进行分类(仅适用于少量商品/层次结构)
我稍微修改了你的代码(我没有测试它,因此可能存在一些语法错误):
//put all recordsets in an array to save second query
while ($row2 = $connector->fetchArray($result2)){
$id = $row2['ID'];
$parents[$id] = array('name' => $row2['name'],'parent' => $row2['parentid']);
}
// show the tree-structure
foreach ($parents as $id => $row){
$pid = $row['parentid'];
while ($pid != 0){ // iterate through all parents until top is reached
echo $parents[$pid]['name'].' -> ';
$pid = $parents[$pid]['parentid'];
}
echo $parents[$id]['name'].' - ';
echo '<br>';
}
回答你的评论:
$parents = array();
$parents[2] = array('ID'=>2,'name'=>'General','parentid'=>0);
$parents[3] = array('ID'=>3,'name'=>'Gadgets','parentid'=>2);
$parents[4] = array('ID'=>4,'name'=>'iPhone','parentid'=>3);
foreach ($parents as $id => $row){
$pid=$id;
$arrTmp= array();
do { // iterate through all parents until top is reached
$arrTmp[]=$pid;
$pid = $parents[$pid]['parentid'];
}while ($pid != 0);
$arrTmp = array_reverse($arrTmp);
foreach($arrTmp as $id){
echo $parents[$id]['name'].' -> ';
}
echo '<br>';
}
打印出来:
一般 - &gt;
一般 - &gt;小工具 - &gt;
一般 - &gt;小工具 - &gt; iPhone - &gt;
答案 2 :(得分:1)
使用OOP可能更容易。只需按parentId
对查询进行排序注意:listChildren方法和底部的打印输出正好表明它已正确列出。我没有解释显示器很重要的问题。
class Element {
public $id;
public $name;
public $parent = null;
public $children = array();
public function __construct($id, $name)
{
$this->id = $id;
$this->name = $name;
}
public function addChild($element)
{
$this->children[$element->id] = $element;
$element->setParent($this);
}
public function setParent($element)
{
$this->parent = $element;
}
public function hasChildren()
{
return !empty($this->children);
}
public function listChildren()
{
if (empty($this->children)) {
return null;
}
$out = array();
foreach ($this->children as $child) {
$data = $child->id . ':' . $child->name;
$subChildren = $child->listChildren();
if ($subChildren !== null) {
$data .= '[' . $subChildren . ']';
}
$out[] = $data;
}
return implode(',', $out);
}
}
$elements = array();
$noParents = array();
while ($row = $connector->fetchArray($result)) {
$elements[$row['id']] = $element = new Element($row['id'], $row['name']);
if (isset($elements[$row['parent']])) {
$elements[$row['parent']]->addChild($element);
} else {
$noParents[] = $element;
}
}
foreach ($noParents as $element) {
if ($element->hasChildren()) {
echo "Element {$element->id} has children {$element->listChildren()}.\n";
} else {
echo "Element {$element->id} has no children.\n";
}
}
答案 3 :(得分:1)
如果您使用 PostgreSQL 作为数据库,则可以使用 connectby()函数创建记录集:
SELECT *
FROM connectby('tableName', 'id', 'parent_id')
AS t(keyid text, parent_keyid text, level int);
我喜欢这个功能,并且在我的代码中一直使用。它可以非常快速地执行一些非常强大的操作,并且您没有像( adjacency 模型)那样维护左/右值。