返回类别树的Mysql查询

时间:2012-07-12 09:14:14

标签: php mysql sql-order-by categories

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

enter image description here

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

  • 主页
  • 产品(编辑)(删除)
  • 产品>产品1(编辑)(删除)
  • 产品>产品2(编辑)(删除)
  • 产品&gt; <产品2>产品2 1(编辑)(删除)
  • 产品&gt; <产品2>产品2 2(编辑)(删除)
  • 联系我们(编辑)(删除)

我希望mysql查询结果的顺序与上面显示的顺序相同。我不知道我怎么能实现它。

SELECT *
FROM tbl_categories
ORDER BY ???

请指导。

3 个答案:

答案 0 :(得分:2)

没有单个SQL查询可以根据您的预期方式为您带来结果。

有两种方法可以解决这个问题:

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

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

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

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

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

      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

    3. 请注意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,...

      2. 如果您搜索MPTT PHP MySQL,可以使用代码找到更详细的示例。关于这个主题有很多教程。

答案 1 :(得分: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);

在这个功能中,我已经做了一个健全性检查,以避免无限循环..

答案 2 :(得分:0)

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