Php 多维数组(父数组和子数组)

Php 多维数组(父数组和子数组),php,multidimensional-array,nested,Php,Multidimensional Array,Nested,我在MySQL数据库中有一个分类系统,有父母和孩子。数据库仅存储其直接父级的id,如果在根上,则存储0。由于系统允许多个子类别,因此存在多个孩子的情况 比如说 [98] Storage [1] External [3] Pendrives [4] Portable hhdds [2] Internal [5] Sata hhdd [6] IDE hhdd [...] [99] Clothing 数据库将是 id

我在MySQL数据库中有一个分类系统,有父母和孩子。数据库仅存储其直接父级的id,如果在根上,则存储0。由于系统允许多个子类别,因此存在多个孩子的情况

比如说

[98] Storage
    [1] External
        [3] Pendrives
        [4] Portable hhdds
    [2] Internal
        [5] Sata hhdd
        [6] IDE hhdd
[...]
[99] Clothing
数据库将是

id    parent_id    name
1     98           External
2     98           Internal
3     1            Pendrives
4     1            Portable
5     2            Sata
6     2            IDE
98    0            Storage
99    0            Clothing
我还有一个带有类别id的products表,我需要获得第一级类别中所有产品的列表

例如:

Product   Category
 A          3
 B          4
 C          5
 D          6
 E          74
应该回来 98:A、B、C、D 99:X,Y,Z

我被卡住了,我想不出用那种方式找回它的逻辑

我首先通过以下方式获取不在第一级的所有类别的ID:

while ($row = mysql_fetch_assoc($result)) {
    if ($row['parent_id'] != 0) {
        $level1[$i]['name'] = utf8_encode($row['categories_name']);
        $level1[$i]['id'] = $row['categories_id'];
    }

    $i++;
}
但我已经精疲力竭了,想不出一个办法可以让它们安顿下来。我想了一会儿,但它是无限的:P

有什么想法吗?

我知道有一个完美的方法可以正确地做到这一点,而且mysql的性能很好,我不能相信这个想法,我只是从捷克语翻译过来的

您需要这样的树结构:

类别 身份证件 lft,-左侧索引迭代-左侧编号 rgt,-右迭代上的索引-右迭代上的编号 深度 如何显示完整的树: 当以多个级别的有序列表显示时,必须检测当前节点和下一个项目之间的连接

为面包屑导航获取它: 将子节点添加到需要的任何位置 删除完整的子项 如果你知道这个算法的更多信息或名称,请告诉我


我建议使用PDO编写此文件。

使用递归函数获取所有子类别:

//fetch category structure data
$childCategories = array();
$result = mysql_query("SELECT id, parent_id FROM categories");
while ($row = mysql_fetch_assoc($result)) {
    if ($row['parent_id']) {
        if (!isset($childCategories[$row['parent_id']])) $childCategories[$row['parent_id']] = array();
        $childCategories[$row['parent_id']][] = $row['id'];
    }
}

function getRecursiveCategories($id, $childCategories) {
    $ret = array();
    if (!isset($childCategories[$id])) return $ret;
    foreach ($childCategories[$id] as $childId) {
        $ret[] = $childId;
        $ret = array_merge($ret, getRecursiveCategories($childId, $childCategories));
    }
    return $ret;
}

$cateoryIds = getRecursiveCategories(98, $childCategories);

//now you can query the products
"SELECT * FROM products WHERE category_id IN (".implode(',', $cateoryIds).")";

递归函数调用怎么样?例如:

$allItems = Array();
function getAllItems($category) {
    global $allItems;
    $query = mysql_query("SELECT `id` FROM `categories` WHERE `parent_id` = '".$category."' ");

    if(mysql_num_rows($query)) {
        while($cat = mysql_fetch_assoc($query)) {
            $itemQuery = mysql_query("SELECT * FROM `items` WHERE `category` = '".$cat['id']."' ");
            if(mysql_num_rows($itemQuery)) {
                while($item = mysql_fetch_assoc($itemQuery)) {
                    $allItems[$item['id']] = $item; //using $item['id'] to avoid duplicating items if they are in several categories
                }
            }
            $checkSubCatQuery = "SELECT `id` FROM `categories` WHERE `parent_id` = '".$cat['id']."' LIMIT 1");
            if(mysql_num_rows($checkSubCatQuery)) { //Checking to see if we have a sub category
                getAllItems($cat['id']); //Calling agait to get all items from sub cattegory of the current category
            }
        }
    }
}

当然,它总是可以被优化的。

按照以下步骤应该可以做到这一点,算法可以提高效率:

首先,根据初始类别ID进行选择。类似于“选择ID”、“类别的父项ID”的内容将结果存储在如下数组中:

$catArr = array(
   array(1,98),
   array(2,98),
   ...
  );
对以下函数运行此操作注意:$start=98

function getSubsets($catArr, $start) {
   $rtn = array();
   foreach($catArr as $cat) {
      if($cat[1] == $start) { 
         $rtn[] = $cat[0];
         $subcats = getSubsets($catArr,$cat[0]);
         foreach($subcats as $subcat) { $rtn[] = $subcat; }
      }
   }
   return $rtn;
}

note: never have a category be its own parent or any other similar 
conditions that would cause an infinite loop.
现在,您的最终SQL可以这样生成

 $sql = "SELECT * FROM products WHERE category IN (".implode(',', $rtn).")"; 
 Note: this assumes category is a number

最后一点注意:您只运行两个SQL查询:

这是1NF使任务更简单的地方。谢谢,但我不能修改db,因为它是由其他人开发的工作系统,我只是插入这将生成每个子类别的查询,这正是我试图避免的。
mysql_query("START TRANSACTION");
$row = mysql_fetch_assoc(mysql_query("SELECT * FROM categories WHERE id = " . intval($_GET["id"]) . " FOR UPDATE"));
mysql_query("DELETE FROM categories WHERE lft >= $row[lft] AND rgt <= $row[rgt]");
$rozdil = $row["rgt"] - $row["lft"] + 1;
mysql_query("UPDATE categories SET lft = lft - $rozdil WHERE lft > $row[rgt]");
mysql_query("UPDATE categories SET rgt = rgt - $rozdil WHERE rgt > $row[rgt]");
mysql_query("COMMIT");
//fetch category structure data
$childCategories = array();
$result = mysql_query("SELECT id, parent_id FROM categories");
while ($row = mysql_fetch_assoc($result)) {
    if ($row['parent_id']) {
        if (!isset($childCategories[$row['parent_id']])) $childCategories[$row['parent_id']] = array();
        $childCategories[$row['parent_id']][] = $row['id'];
    }
}

function getRecursiveCategories($id, $childCategories) {
    $ret = array();
    if (!isset($childCategories[$id])) return $ret;
    foreach ($childCategories[$id] as $childId) {
        $ret[] = $childId;
        $ret = array_merge($ret, getRecursiveCategories($childId, $childCategories));
    }
    return $ret;
}

$cateoryIds = getRecursiveCategories(98, $childCategories);

//now you can query the products
"SELECT * FROM products WHERE category_id IN (".implode(',', $cateoryIds).")";
$allItems = Array();
function getAllItems($category) {
    global $allItems;
    $query = mysql_query("SELECT `id` FROM `categories` WHERE `parent_id` = '".$category."' ");

    if(mysql_num_rows($query)) {
        while($cat = mysql_fetch_assoc($query)) {
            $itemQuery = mysql_query("SELECT * FROM `items` WHERE `category` = '".$cat['id']."' ");
            if(mysql_num_rows($itemQuery)) {
                while($item = mysql_fetch_assoc($itemQuery)) {
                    $allItems[$item['id']] = $item; //using $item['id'] to avoid duplicating items if they are in several categories
                }
            }
            $checkSubCatQuery = "SELECT `id` FROM `categories` WHERE `parent_id` = '".$cat['id']."' LIMIT 1");
            if(mysql_num_rows($checkSubCatQuery)) { //Checking to see if we have a sub category
                getAllItems($cat['id']); //Calling agait to get all items from sub cattegory of the current category
            }
        }
    }
}
$catArr = array(
   array(1,98),
   array(2,98),
   ...
  );
function getSubsets($catArr, $start) {
   $rtn = array();
   foreach($catArr as $cat) {
      if($cat[1] == $start) { 
         $rtn[] = $cat[0];
         $subcats = getSubsets($catArr,$cat[0]);
         foreach($subcats as $subcat) { $rtn[] = $subcat; }
      }
   }
   return $rtn;
}

note: never have a category be its own parent or any other similar 
conditions that would cause an infinite loop.
 $sql = "SELECT * FROM products WHERE category IN (".implode(',', $rtn).")"; 
 Note: this assumes category is a number