Mysql树形表的两种查询方案(递归与自连接)

你有没有遇到过这样一种情况:
一张表就实现了一对多的关系,并且表中每一行数据都存在“爷爷-父亲-儿子-…”的联系,这也就是所谓的树形结构
在这里插入图片描述
对于这样的表很显然想要通过查询来实现价值绝对是不能只靠select * from table 来实现的,下面提供两种解决方案:

1.自连接

inner join 关键可以实现多种分类的查询,其实SQL很简单

SELECT
	one.id one_id,
	one.label one_label,
	two.id two_id,
	two.label two_label
FROM
	course_category one
	INNER JOIN course_category two ON two.parentid=one.id
	INNER JOIN course_category three ON three.parentid=two.id
	WHERE one.id='1' AND one.is_show='1' AND two.is_show='1'
	ORDER BY one.orderby,two.orderby

也是规规矩矩的就查出一整棵树
在这里插入图片描述
这种查询的原则就是通过parentId去实现,“爷爷找爸爸,爸爸找儿子,儿子找孙子”,下面来逐帧慢放:
1.one在这里插入图片描述
2.one,two
在这里插入图片描述
3.one,two,three
在这里插入图片描述
可以看到,只有在树的层级确定的情况下我才能选择性的去自连接子表,某种意义上来讲这种方法存在弊端,我要是insert进去层级更低的新子节点那我的sql就得改变,从而就造成了一个“动一发而牵全身”的硬编码问题,实在是不够稳妥!

2.递归!

向上递归

首先声明,如果mysql的版本低于8是不支持递归查询的函数的!
下面来看一下如何用递归优雅的实现,从树根查到树顶:
先来看一个简单的Demo

	with RECURSIVE t1 AS(
		SELECT 1 AS n
		union all
		SELECT n+1 FROM t1 WHERE n<5
	)
	SELECT * from t1

在这里插入图片描述
该怎么理解这每一步呢?
WITH RECURSIVE t1 AS:
这是递归查询的开始,创建了一个名为t1的递归表。
SELECT 1 AS n:
在t1表中,插入了一个初始行,值为1,命名为n。
UNION ALL:
使用UNION ALL运算符将初始行和递归查询结果合并,形成递归步骤。这也就是下次递归的起点表
SELECT n+1 FROM t1 WHERE n<5:
递归部分的查询,从t1表中选择n加1的结果,当n小于5时进行递归。
SELECT * FROM t1:
最终查询,返回t1表的所有行。
其实在使用递归的过程只需要注意要去避免死龟就好!
如何去查开头的那张树形表呢?这样就好:

with recursive temp as (
select * from  course_category p where  id= '1'
 union all
select t.* from course_category t inner join temp on temp.id = t.parentid
)
select *  from temp order by temp.id, temp.orderby

下面我们逐帧分析:
在这里插入图片描述
其实关键的地方就在于第三步,在树根的基础上去找叶子:
神之一手:
select t.* from course_category t inner join temp on temp.id = t.parentid
这就是递归相较于第一种方式可以无视层级inner jion的关键,因为这个动作已经被递归自动完成了,递归巧妙地一点就在这里!

向下递归

基于向上递归父找子的思想,向下递归则是子找父,即在叶子基础上union all之后去找根
子的parentId=父的id

with recursive temp as (
select * from  course_category p where  id= '1-1-1'
 union all
select t.* from course_category t inner join temp on temp.parentid = t.id  
//temp表是下次递归的基础
)
select *  from temp order by temp.id, temp.orderby

值得注意的是Mysql为了避免无限递归递归次数为1000次,也可以人为来设置cte_max_recursion_depth和max_execution_time来自定义递归深度和执行时间
使用递归的好处无需言语,一次io连接就搞定了全部

  • 21
    点赞
  • 53
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 13
    评论
### 回答1: MySQL实现递归查找树形结构可以通过使用WITH RECURSIVE和UNION ALL语句来实现。以下是一个示例查询: 假设我们有一个名为“category”的,其中包含以下列:id、name和parent_id,其中parent_id列包含一个指向同一中的父类别的外键。 我们可以使用以下查询递归地查找树形结构: ``` WITH RECURSIVE category_tree (id, name, parent_id, depth) AS ( SELECT id, name, parent_id, 0 FROM category WHERE parent_id IS NULL # 根节点 UNION ALL SELECT c.id, c.name, c.parent_id, ct.depth + 1 FROM category c JOIN category_tree ct ON c.parent_id = ct.id ) SELECT id, name, parent_id, depth FROM category_tree; ``` 在此查询中,我们首先选择根节点,然后使用UNION ALL语句递归地选择所有子节点。使用WITH RECURSIVE语句和递归查询,我们可以轻松地构建树形结构,并根据需要进行任何进一步的处理。 ### 回答2: MySQL是一种关系型数据库管理系统,它本身并不支持递归查询,但可以通过多联接和递归实现树形结构查询。 在MySQL中,可以使用两种方式来实现树形结构递归查询:使用递归函数或使用临时。 使用递归函数可以实现树形结构递归查询,该函数可以通过递归的方式查询树形结构中的子节点,并将结果集逐层汇总。递归函数通常包括两部分:基准查询递归查询。基准查询用于获取初始节点的直接子节点,递归查询则用于获取每个子节点的子节点,依次类推。通过将基准查询递归查询结合起来,并使用UNION ALL将结果集合并,就可以得到完整的树形结构。然后可以使用JOIN等操作将查询结果与其他进行联接,实现更复杂的查询功能。 另一种方式是使用临时来实现树形结构递归查询。首先,创建一个临时,其中包含树形结构的节点和其父节点的信息。然后使用一个循环将树形结构中的节点逐层加入到临时中,直到所有节点都被添加进去。最后,使用JOIN等操作将临时与其他进行联接,实现需要的查询功能。 无论使用哪种方式,实现树形结构递归查询都需要注意两个问题:首先是递归的结束条件,即确定递归何时停止;其次是性能问题,树形结构可能非常复杂,递归查询消耗的资源和时间都较大,需要综合考虑查询效率和系统性能。 总的来说,通过合理地使用递归函数或临时,结合适当的查询操作,可以在MySQL中实现树形结构递归查询,并完成需要的查询功能。 ### 回答3: MySQL是一种关系型数据库管理系统,它本身不支持递归查询树形结构的存储。但是,我们可以利用MySQL的一些特性来实现递归查找树形结构。 实现递归查询树形结构的方法有很多种,以下是其中一种常用的方法: 1. 为每个节点添加一个字段,用于记录节点的父节点ID; 2. 创建一个递归查询函数,用于查找节点的子节点,并将结果保存到一个临时中; 3. 递归调用该函数,直到找到所有节点的子节点; 4. 使用JOIN语句将各个临时连接起来,得到完整的树形结构。 具体步骤如下: 1. 创建一个来存储树形结构的节点信息,中包含节点ID、节点名称和父节点ID等字段; 2. 创建一个存储递归查询结果的临时; 3. 创建一个存储递归调用所需参数的存储过程或函数,参数包括父节点ID、递归深度和临时名等; 4. 在存储过程或函数中,使用SELECT INTO语句查询满足条件的子节点,并将结果插入到临时中; 5. 在存储过程或函数中,使用递归调用语句调用自身,并传递子节点作为父节点ID; 6. 在存储过程或函数中,使用条件判断语句来停止递归,例如判断是否已经到达最深层级或没有更多子节点; 7. 在主程序中,调用存储过程或函数,并使用JOIN语句将各个临时连接起来,得到完整的树形结构。 通过以上步骤,我们可以利用MySQL的一些特性,实现递归查询树形结构的存储。但需要注意的是,这种方法可能会对数据库性能造成一定的影响,因此在实际应用中需要根据具体情况进行优化和调整。
评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

懒羊羊.java

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值