【问题标题】:How to display categories, subcategories, sub-subcategories in select list - php/mysql?如何在选择列表中显示类别、子类别、子子类别 - php/mysql?
【发布时间】:2014-08-01 16:40:07
【问题描述】:

我想在选择列表(下拉列表)中显示类别、子类别和子子类别,就像 WordPress 在其管理面板中显示的方式一样。先看看我的数据库表(tb_categories)-

我想要以下 HTML 格式的输出 -

“无”和“未分类”这两项在代码中是硬编码的。我想知道如何使用选择列表选项按层次顺序显示类别及其子类别。

我正在尝试使用自联接的以下 sql 查询。在这里——

SELECT
    `cat`.`category_name` AS 'category name',
    `cat2`.`category_name` AS 'parent category'
FROM
    `tb_categories` AS `cat`
LEFT JOIN `tb_categories` AS `cat2` ON `cat`.`category_parent` = `cat2`.`category_id`
ORDER BY
    'parent category'

它给出的输出是 -

Array
(
    [0] => Array
        (
            [0] => My Parent Category
            [category name] => My Parent Category
            [1] => 
            [parent category] => 
        )

    [1] => Array
        (
            [0] => Parent Category 2
            [category name] => Parent Category 2
            [1] => 
            [parent category] => 
        )

    [2] => Array
        (
            [0] => Parent Category 3
            [category name] => Parent Category 3
            [1] => 
            [parent category] => 
        )

    [3] => Array
        (
            [0] => My Child Category
            [category name] => My Child Category
            [1] => My Parent Category
            [parent category] => My Parent Category
        )

    [4] => Array
        (
            [0] => Sports
            [category name] => Sports
            [1] => 
            [parent category] => 
        )

    [5] => Array
        (
            [0] => Cricket is best
            [category name] => Cricket is best
            [1] => Sports
            [parent category] => Sports
        )

    [6] => Array
        (
            [0] => AJAX
            [category name] => AJAX
            [1] => 
            [parent category] => 
        )

    [7] => Array
        (
            [0] => hockey is best
            [category name] => hockey is best
            [1] => Sports
            [parent category] => Sports
        )

)

我不知道甚至不确定如何在该选择列表中显示上述数据。我们如何做到这一点?我们如何使用连接来做到这一点?如果我们使用连接,那么我们是否需要一些数组来存储和排序结果?还有我们如何在一个循环中使用多个查询来做到这一点?哪种方法最好?

【问题讨论】:

  • 我们如何在一个循环中处理多个查询?我们没有。
  • 您还应该选择 id 和 parent_id。否则,当两个类别具有相同名称时,就无法构建结构。然后你应该用递归函数来做。
  • 两个类别不能有相同的名称。它在验证中。但是如何使用递归函数呢?
  • 我删除了我的答案,因为实际上这不是一个很好的例子。它可能导致许多同时查询和一堆数据库往返。 Hellcode 的要好得多。
  • 好的。但我不明白如何将选项值 = 类别 ID 放在选择列表中?

标签: php mysql sql


【解决方案1】:

这是最简单的分类表结构

+-------------------------+
| categories              |
+-------------------------+
| category_id   (int)     | PK
| parent_id     (int)     | Index
| category_name (varchar) |
| ...                     |
+-------------------------+

下面的函数将递归地获取所有类别并构建层次结构。如您所见,您可以选择要预选的值,也可以仅获取层次结构的一部分更改父值。

function build_category_tree(&$output, $preselected, $parent=0, $indent=""){
  $r = mysql_query("
    SELECT category_id, category_name FROM categories WHERE parent_id = " . $parent . "
  ");

  while($c = mysql_fetch_array($r, MYSQL_ASSOC)){
    $selected = ($c["category_id"] == $preselected) ? "selected=\"selected\"" : "";
    $output .= "<option value=\"" . $c["category_id"] . "\" " . $selected . ">" . $indent . $c["category_name"] . "</option>";
    if($c["category_id"] != $parent){
      build_category_tree($output, $preselected, $c["category_id"], $indent . "&nbsp;&nbsp;");
    }
  }
}

用法:

<?php 
build_category_tree($categories, 0); 
// if you want to preselect a value and start from some subcategory
build_category_tree($categories, 5, 2); 
?>

<!-- HTML -->
<select><?php echo $categories ?></select>
<!-- if you want to add some extra options -->
<select>
  <option value="-1">Choose a category</option> 
  <?php echo $categories ?>
</select>

旁注:虽然这个功能看起来很优雅,但如果你有成千上万个类别,请不要使用它。此外,在您的最终版本中使用 MySQLi 或 PDO_MySQL 扩展。

【讨论】:

  • 你的解决方案也不错,但是如果我们有几个类别,为什么我们可以使用这个功能?它会减慢系统速度吗?
  • @user3779493 仅当您有超过一万个深度为五个或更多级别的类别时。否则,在任何父子结构中使用它。
【解决方案2】:

假设您给定的数组在 $array 中,您可以使用它。但正如我已经告诉过你的那样,你应该选择 id 来处理同名的类别并将它们用作选择框中的选项值:

  $options = get_options($array);
  echo "<select>";
  foreach($options as $val) {
    echo "<option>".$val."</option>";
  }
  echo "</select>";

  function get_options($array, $parent="", $indent="") {
    $return = array();
    foreach($array as $key => $val) {
      if($val["parent category"] == $parent) {
        $return[] = $indent.$val["category name"];
        $return = array_merge($return, get_options($array, $val["category name"], $indent."&nbsp;&nbsp;&nbsp;"));
      }
    }
    return $return;
  }

假设您现在将数组中的 id 作为“category_id”和“parent_category_id”,您可以使用它。 $return 中键之前的“x”只是为了避免 php 更改您的键,因为它们是数字。

  $options = get_options($array);
  echo "<select>";
  foreach($options as $key => $val) {
    echo "<option value='".substr($key,1)."'>".$val."</option>";
  }
  echo "</select>";

  function get_options($array, $parent=0, $indent="") {
    $return = array();
    foreach($array as $key => $val) {
      if($val["parent_category_id"] == $parent) {
        $return["x".$val["category_id"]] = $indent.$val["category name"];
        $return = array_merge($return, get_options($array, $val["category_id"], $indent."&nbsp;&nbsp;&nbsp;"));
      }
    }
    return $return;
  }

【讨论】:

  • 感谢 frz。它可以工作,但是我如何将类别 ID 放入选项值中,因为我没有 100% 遵循代码。我正在查询中获取类别 ID,但我该如何使用它?
  • @user3779493:我现在添加了带有 id 的函数。
  • 实际上我也试图在合并后保留索引(键),但它们都在重新索引。您添加字符“x”的解决方法既好又棘手,但我发现另一种解决方法我们根本不需要合并。我们可以简单地进行联合,即添加两个数组。我这样做了 - $return[$val["Category ID"]] = $indent . $val["Category Name"]; $return += get_options($categories, $val["Category ID"], $indent . "&amp;nbsp;&amp;nbsp;&amp;nbsp;"); 并且还更改了行 echo "&lt;option value='" . $key . "'&gt;" . $val . "&lt;/option&gt;";
  • @hellcode:如何在表格中打印,例如 cat -> cat 1 -> cat 1.1
【解决方案3】:

Database View For Categories

$con = mysqli_connect("localhost","root","","categories"); 
if (mysqli_connect_errno())
  {
  echo "Failed to connect to MySQL: " . mysqli_connect_error();
}
$sql = mysqli_query($con,"SELECT `cat`.`categoryName` AS 'category name', `cat2`.`categoryName` AS 'parent category' FROM `product_category` AS `cat` LEFT JOIN `product_category` AS `cat2` ON `cat`.`parentId` = `cat2`.`categoryId` where `cat2`.`categoryName` !='NULL' order by `cat2`.`categoryName`");

  while($res=mysqli_fetch_array($sql,MYSQLI_ASSOC)){
  $cat[] = $res['category name'];
  $parent[]= $res['parent category'];
}
$parents = "";
for($i=0;$i<count($cat);$i++){
 if($parents!=$parent[$i]){
if($i!=0){ echo "</ul>"; }
 echo $parent[$i]."<ul><li>".$cat[$i]."</li>" ;
}else{

 echo "<li>".$cat[$i]."</li>" ;
}
$parents = $parent[$i];
}
echo "</ul>";

Output

Form 更多关于php、ajax、jquery、mysql、面试题的教程。请查看我的博客 hackandphp.com

【讨论】:

  • 你的做法也很棒。你做了自加入而不是递归函数。谢谢。
  • 感谢您提出我的解决方案的评论。谢谢。
猜你喜欢
  • 1970-01-01
  • 2020-05-06
  • 2012-10-14
  • 2011-07-14
  • 2019-06-20
  • 1970-01-01
  • 2019-03-31
  • 2017-07-10
  • 1970-01-01
相关资源
最近更新 更多