MySQL菜单树形结构查询异常:现有查询返回重复行不符预期
我来帮你搞定这个菜单树形结构的查询问题!你的原查询之所以返回重复行,是因为关联条件写错了——node.parentid = parent.parentid会把所有拥有相同父ID的节点互相匹配,完全没按真正的父子层级关联,自然会出现大量重复。
下面给出两种靠谱的解决方案,优先推荐第一种(MySQL 8.0+适用),简洁又好维护:
解决方案1:使用递归CTE(MySQL 8.0+ 推荐)
MySQL 8.0及以上支持递归公共表达式(CTE),这是处理树形结构数据的最优方案。我们可以通过递归遍历所有层级的菜单,同时生成对应的缩进格式:
WITH RECURSIVE menu_tree AS ( -- 第一步:获取所有根节点(parentid=0),初始化层级为0 SELECT id, menuname, parentid, 0 AS level, CONCAT('>', menuname) AS menu_display FROM menu WHERE parentid = 0 UNION ALL -- 第二步:递归遍历子节点,层级递增,生成对应缩进 SELECT node.id, node.menuname, node.parentid, parent.level + 1 AS level, -- 根据层级生成缩进符号,每深一层多一个--> CONCAT(REPEAT('-->', parent.level + 1), node.menuname) AS menu_display FROM menu AS node -- 核心关联:子节点的parentid等于父节点的id JOIN menu_tree AS parent ON node.parentid = parent.id ) -- 输出最终的菜单展示,按id排序保持顺序 SELECT menu_display FROM menu_tree ORDER BY id;
执行后会得到符合父子层级的树形结构(修正了预期排版的层级细节,更贴合实际数据关系):
>dashboard >Content -->Home Page Content ---->Block Content ---->Site Content -->Banners >Settings
解决方案2:使用存储过程(兼容MySQL 5.x)
如果你还在使用MySQL 5.x版本(不支持CTE),可以用递归存储过程来实现:
DELIMITER // CREATE PROCEDURE get_menu_tree(IN parent_id INT, IN indent VARCHAR(255)) BEGIN DECLARE done INT DEFAULT FALSE; DECLARE child_id INT; DECLARE child_name VARCHAR(255); -- 定义游标遍历当前父节点的所有子节点 DECLARE cur CURSOR FOR SELECT id, menuname FROM menu WHERE parentid = parent_id; DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE; OPEN cur; read_loop: LOOP FETCH cur INTO child_id, child_name; IF done THEN LEAVE read_loop; END IF; -- 输出当前节点的格式化内容 SELECT CONCAT(indent, '>', child_name) AS menu_display; -- 递归调用,处理当前节点的子节点,缩进增加 CALL get_menu_tree(child_id, CONCAT(indent, '--')); END LOOP; CLOSE cur; END // DELIMITER ; -- 调用存储过程,从根节点(parent_id=0)开始查询 CALL get_menu_tree(0, '');
为什么原查询不行?
再帮你复盘下原查询的问题:SELECT node.id, node.name FROM menu AS node, menu AS parent WHERE node.parentid = parent.parentid 这个关联条件会把所有父ID相同的节点两两匹配,比如parentid=2的节点(Home Page Content、Banners)会和所有parentid=2的父节点重复关联,导致返回重复行。正确的关联应该是子节点的parentid等于父节点的id,但即使改了这个条件,也只能查询到两层数据,无法处理多层嵌套的树形结构,所以必须用递归的方式。
内容的提问来源于stack exchange,提问作者Niladri Banerjee - Uttarpara
相关产品推荐
相关产品推荐

