数据库语句的递归查询求助

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据库语句的递归查询求助相关的知识,希望对你有一定的参考价值。

如图,在数据库中,除了最顶上的结点,每个结点都有一个 user_id 和 parent_id,user_id指的是结点本身,panrent_id指的是本结点的父结点,我现在知道了图中的user_id为32的一个结点,我想找出这个结点下面的所有的节点(包括它自己)的user_id,请问这个用mysql的数据库语句怎么实现?谢谢了!

应该是这样:

with qry as (select user_id,parent_id from tab where user_id = 32
union all
select tab.user_id,tab.parent_id from tab,qry
where tab.parent_id = qry.id)
select * from qry ;

我用mysql5.0.22,不支持上述语法,oracle就可以(sqlserver应该也可以):
create table tab1(user_id int, parent_id int);
insert into tab1 values(1,null);
insert into tab1 values(32,1);
insert into tab1 values(101,32);
insert into tab1 values(102,32);
insert into tab1 values(201,101);
insert into tab1 values(202,101);
insert into tab1 values(203,102);
insert into tab1 values(204,102);
select * from tab1;
with qry(user_id,parent_id) as (select user_id,parent_id from tab1 where user_id = 32
union all
select tab1.user_id,tab1.parent_id from tab1,qry
where tab1.parent_id = qry.user_id
)
select * from qry;

所以,mysql没有办法了,只有写函数,用循环来实现了。
参考技术A 就和C++写递归一样的吧~~
do while,如果这个点没有子节点了,就返回上一个节点
参考技术B 写一个函数,只查询某个节点的子节点,然后递归保存 参考技术C -------- 写一个自定义函数 ---------

delimiter //
drop function if exists getChildren //
create function getChildren(pid int) returns varchar(500)
begin
declare childrenId varchar(500);
declare temp varchar(300);
set childrenID = "";
set temp = cast(pid as char);
while not isnull(temp) do
set childrenId = concat(childrenId, ",", temp);
select group_concat(user_id) into temp from 你的表名 where find_in_set(parent_id, temp) > 0;
end while;
return childrenId;
end //
delimiter ;
------------------
下面是调用的测试示例
------------------
mysql> select * from tree_recursion;
+----+--------+
| id | parent |
+----+--------+
| 1 | NULL |
| 2 | 1 |
| 3 | 1 |
| 4 | 2 |
| 5 | 2 |
| 6 | 3 |
| 7 | 4 |
| 8 | 5 |
| 9 | 8 |
+----+--------+
9 rows in set (0.00 sec)
mysql> # 找节点 2 下的所有结点
mysql>
mysql> delimiter //
mysql> drop function if exists getChildren //
Query OK, 0 rows affected (0.00 sec)
mysql> create function getChildren(pid int) returns varchar(500)
-> begin
-> declare childrenId varchar(500);
-> declare temp varchar(300);
->
-> set childrenID = "";
-> set temp = cast(pid as char);
->
-> while not isnull(temp) do
-> set childrenId = concat(childrenId, ",", temp);
-> select group_concat(id) into temp from tree_recursion where find_in_set(parent, temp) > 0;
-> end while;
->
-> return childrenId;
-> end //
Query OK, 0 rows affected (0.00 sec)
mysql>
mysql> delimiter ;
mysql>
mysql> select * from tree_recursion where find_in_set(id, getChildren(2));
+----+--------+
| id | parent |
+----+--------+
| 2 | 1 |
| 4 | 2 |
| 5 | 2 |
| 7 | 4 |
| 8 | 5 |
| 9 | 8 |
+----+--------+
6 rows in set (0.02 sec)
mysql>
参考技术D 我之前也遇到你这样的问题, 如果打算用一条SQl查询某个节点下面的所有叶子节点话,需要在表的结果设计上做点功夫,比如做类似这样的表结构,
ClassID 表示当前节点 类别ID
ClassName 表示当前节点 类别名称
ParentID 表示当前的父亲节点ID
Parent_Path----------->这个列比较关键 就是记录当前节点到 根节点的整个路径如数据0,1,11,111

这样 你在用Sql语句时候查询时候 ,比如查询ClassID =9的所有子节点,Sql 语句就可以这样写Parent_Path like '%,9,%'
希望对你有帮助

求助一条mysql 更新 语句 where 后面为查询的结果

求助一条sql 语句
表 a 字段 aa , ab
表 b 字段 ab
更新 表a 字段 aa 为1 当 表a 字段ab = 表 b 字段 ab
update a set aa = '1' where 后面怎么写呢
谢谢

update a set aa = \'1\' where ab = ( select ab from b);
测试过了 可以通过
但是这个语句只有在 b表中只有一条记录的时候是准确的
如果b表中有多条记录 那你得在子查询中查询指定的某一个 ab 列的值 才是准确的!追问

提示错误是 #1242 - Subquery returns more than 1 row
b表中有很多记录呢
你的意思是 select ab from b 只有一条结果是吗

追答

如果有很多记录的话
假设我们要找 b表中id 为 100 的记录的 ab 和 a表的ab相同的时候
update a set aa=\'1\' where ab = (select ab from b where id=100);
这样就可以了 这样的话整个查询语句的含义是
修改 a 表中的 aa 字段的值为 1 条件是 a 表中的 ab字段和
b 表中的 id 为 100 的 ab 数据相同的

毕竟 a 表和 b 表是不同的2个表 如果 b表中只有仅仅一个数据的话 没关系

具体你的 b表的 ab的数据都是写什么 在什么情况下要把他们修改告诉我把

参考技术A update a, b set a.aa=1 where a.ab=b.ab追问

好像不行啊

追答

报什么错呢

追问

这个可以了
我还想 :
当 b中 有2个ab 的值等于a中ab值 a.aa=2
当 b中 有3个ab 的值等于a中ab值 a.aa=3

参考技术B update a,b set aa='1' where a.ab=b.ab 参考技术C where a.ab=b追问

where a.ab = b.ab ???

追答

嗯 后面AB没看到 B.AB

以上是关于数据库语句的递归查询求助的主要内容,如果未能解决你的问题,请参考以下文章

mysql递归查询语句

递归SQL语句

SQL递归查询知多少

使用Oracle数据库的递归查询语句生成菜单树

sql 递归查询

PostgreSQL递归查询示例