6

我正在从事品类管理。我在每一行都有 parentId。类别可以是 n 级。我可以递归调用 php 函数,该函数将返回类别树数组。

在此处输入图像描述

现在的问题是:在管理面板中,我想要如下所示的类别列表页面。即属于哪个类别。

  • 产品(编辑)(删除)
  • 产品 > 产品 1(编辑)(删除)
  • 产品 > 产品 2(编辑)(删除)
  • 产品 > 产品 2 > 产品 2 1(编辑)(删除)
  • 产品 > 产品 2 > 产品 2 2(编辑)(删除)
  • 联系我们(编辑)(删除)

我希望 mysql 查询结果的顺序与上图相同。我不确定如何实现它。

SELECT *
FROM tbl_categories
ORDER BY ???

请指导。

4

3 回答 3

2

您可以使用一个存储函数,该函数将递归地获取根路径并与您的父级连接。

DELIMITER $$
DROP FUNCTION IF EXISTS `get_category`$$
CREATE FUNCTION `get_category`(cat_id int) RETURNS VARCHAR(255)
READS SQL DATA
BEGIN
DECLARE c_id INT;
DECLARE p_id INT;
DECLARE count INT;
DECLARE cat_name VARCHAR(255);
DECLARE cat_path VARCHAR(255);
set c_id = cat_id;
SELECT parent_category_id, category_name INTO p_id, cat_name FROM categories WHERE category_id = c_id;
set c_id = p_id;
set cat_path=cat_name;
set count=0;
WHILE (c_id IS NOT NULL) DO 

SELECT parent_category_id, category_name INTO p_id, cat_name FROM categories WHERE category_id = c_id;
set c_id = p_id;
set cat_path = concat_ws('>',cat_name,cat_path);
set count = count + 1;
IF count=10 THEN
  SET c_id = NULL;
END IF;
 END WHILE;
RETURN cat_path;
END
$$
DELIMITER ;

然后调用使用

select getcategory(category_id);

在此功能中,我进行了完整性检查以避免无限循环。

于 2012-07-12T10:01:44.900 回答
2

没有单一的 SQL 查询可以为您带来基于此表结构的按您期望的方式排序的结果。

解决问题的方法有两种:

  1. 使用外部应用程序逻辑(在 DB 之外)进行递归调用,以发现每个类别的子项并在应用程序中构建树。

  2. 使用其中一种算法将树数据存储在关系数据库中。其中一种算法称为Modified Preorder Tree Traversal或简称为 MPTT。

假设我们使用列lftrgt在遍历中维护左/右索引,当您插入新类别时,您将需要:

  1. 通过 Id 获取父类别信息:SELECT lft,rgt FROM tbl_categories WHERE categoryId=5 让我们假设父类别有lft=7并且rgt=10(在这种情况下它已经有一个孩子)

  2. 为新条目腾出空间 - 将所有记录移动 2(lft 为 1,rgt 为 1):

    UPDATE tbl_categories SET rgt=rgt+2 WHERE rgt>=10 ORDER BY rgt DESC

    UPDATE tbl_categories SET lft=lft+2 WHERE lft>=10 ORDER BY lft DESC

注意这里ORDER降序。由于lftrgt应该是唯一的,所以建议UNIQUE对它们进行约束,然后在更新时需要降序排列,以防止重复键错误。

  1. 设置lft=<former parent rgt>rgt=<former parent rgt +1>插入新记录...

    INSERT INTO tbl_categories SET categoryName="New Child",parentCategoryId=5,lft=11,rgt=12,...

如果您搜索MPTT PHP MySQL. 关于这个主题有很多教程。

于 2012-07-12T09:49:27.563 回答
0

您无法在单个 mysql 查询中实现此目的。那么你可以通过执行多个查询来实现这一点。算法是这样的:最初通过从数据库中获取数据来创建一个您将填充的数据集对象。创建一个以父 ID 作为参数的方法,如果存在则返回其子节点,如果没有子节点则返回 -1。Step1:获取所有没有父(根)节点的行。Step2:遍历这个结果。例如,如果 prod1 和 prod2 是结果集中的初始返回节点。迭代这个 RS 我们得到 prod1,我们在 DataSET obj 中插入一行。然后我们将 prod1 的 id 发送给 getCHILD 方法,以获取它的子节点,然后我们再次迭代返回的结果集,并再次调用 getCHILD 方法,直到我们没有得到最低节点。

于 2012-07-12T09:42:17.617 回答