最近在看公司的OA系统,OA系统中基本都会有节点树,其中对于树上的数据展示,就是用了数据库的递归查询,在这里总结下递归查询。
现在存在如下的一棵树:
不会画树,将就一下,该树对应下面创建的表数据。
创建如下表:
create table DG ( id NUMBER not null, --主键 parent_id NUMBER, -- 父节点 childer_id NUMBER -- 当前节点,当时名字没区号,也表示当前的值,即树中的值 )创建如下数据:(除去最后一条数据,其他的数据与树中的数据严格一致)
insert into DG (id , childer_id)values (goods_seq.nextval , 6); insert into DG (id , Parent_Id , Childer_id) values(goods_seq.nextval,6,10); insert into DG (id , Parent_Id , Childer_Id) values(goods_seq.nextval,10,9); insert into DG (id , Parent_Id , Childer_Id) values(goods_seq.nextval,9,1); insert into DG (id , Parent_Id , Childer_Id) values(goods_seq.nextval,9,2); insert into DG (id , Parent_Id , Childer_Id) values(goods_seq.nextval,6,8); insert into DG (id , Parent_Id , Childer_Id) values(goods_seq.nextval,8,3); insert into DG (id , Parent_Id , Childer_Id) values(goods_seq.nextval,8,4); insert into DG (id , Parent_Id , Childer_Id) values(goods_seq.nextval,10,7); insert into DG (id , Parent_Id , Childer_Id) values(goods_seq.nextval,11,7);查询表中的数据如下
select * from DG ID PARENT_ID CHILDER_ID 1 91.00 6.00 2 92.00 6.00 10.00 3 93.00 10.00 9.00 4 94.00 9.00 1.00 5 95.00 9.00 2.00 6 96.00 6.00 8.00 7 97.00 8.00 3.00 8 98.00 8.00 4.00 9 99.00 10.00 7.00 10 100.00 11.00 7.00查询出来的是全部的数据,但是最后一条数据是不在树这张图上的,因不存在childer_id为11的记录
使用递归查询,查找出树上的全部数据,不在树上的记录不显示,即某条记录的parent_id必须是另一条记录的childer_id,符合该条件的记录都显示出来。递归存在一个入口和一个出口,入口使用start with传入参数,出口就是某条记录不满足这样的条件了
select * from DG start with childer_id = 6 connect by parent_id = prior childer_id;
ID PARENT_ID CHILDER_ID 1 91 6 2 96 6 8 3 97 8 3 4 98 8 4 5 92 6 10 6 99 10 7 7 93 10 9 8 94 9 1 9 95 9 2与上面比较,不在树中的记录已经没有被显示出来了。 根据记录的显示,我们可以看出来记录是按照深度遍历的顺序排序的,而不是按广度遍历的顺序排序的 但是在深度遍历的时候,对于兄弟节点,先遍历哪个,其实是随机的,或者说是按照先插入的数据排在前面,后插入的数据排在后面。 但是如果我们需要按照我们的规则对兄弟节点的顺序进行排序,这样的排序明显不会符合我们。 这里我们假设根据childer_id的大小排序,使用如下SQL:
使用order by排序
select * from DG start with childer_id = 6 connect by parent_id = prior childer_id order by childer_id;
ID PARENT_ID CHILDER_ID 1 96 6 8 2 92 6 10 3 97 8 3 4 98 8 4 5 94 9 1 6 95 9 2 7 93 10 9 8 99 10 7 9 100 11 7 10 91 6虽然按照parent_id来进行排序了,但是整个结果都是按照parent_id来排序了,不再满足深度遍历的顺序,也就是不分层次了,这样的结果明显不是我们想要的。其实除去不在树中的那条记录外,这样的排序时跟下面的排序一致的
select * from DG ORDER BY PARENT_ID;仍然按照深度遍历的顺序排序,但是兄弟节点的排序,使用order sibings by
select * from DG start with childer_id = 6 connect by parent_id = prior childer_id order siblings by childer_id;
ID PARENT_ID CHILDER_ID 1 91 6 2 96 6 8 3 97 8 3 4 98 8 4 5 92 6 10 6 99 10 7 7 93 10 9 8 94 9 1 9 95 9 2观察整个表的记录,满足了深度遍历的排序,观察3,4 和6,7这两组记录发现兄弟节点的排序已经被我们控制了,用的就是order siblings by
5.获取每条记录的根节点,使用conect_by_root(field)函数
select DG.*, connect_by_root(childer_id) as childer_root , connect_by_root(parent_id) as parent_root , connect_by_root(id) as id_root from DG start with childer_id = 6 connect by parent_id = prior childer_id ID PARENT_ID CHILDER_ID CHILDER_ROOT PARENT_ROOT ID_ROOT 91 6 6 91 96 6 8 6 91 97 8 3 6 91 98 8 4 6 91 92 6 10 6 91 99 10 7 6 91 93 10 9 6 91 94 9 1 6 91 95 9 2 6 91 --其中parent_root这一列是没有数据的,因为根节点对应的记录是没有parent_id值的这样就获取了每条记录的根节点。因为查询出来的记录都是在一棵树上的,所以肯定所有记录的根节点信息都是相同的,通常,我们都是查找某一条记录的根节点,只要加个条件就可以了,如下:
select DG.*, connect_by_root(childer_id) as childer_root , connect_by_root(parent_id) as parent_root , connect_by_root(id) as id_root from DG where childer_id = 4 start with childer_id = 6 connect by parent_id = prior childer_id ID PARENT_ID CHILDER_ID CHILDER_ROOT PARENT_ROOT ID_ROOT 98 8 4 6 空 916.获取记录的在树上的层次(用数字表示,第一层是1,level)和是否是叶子节点(0表示不是,1表示是,connect_by_isleaf)
select id , parent_id , childer_id , level , connect_by_isleaf from DG start with childer_id = 6 connect by parent_id = prior childer_id; ID PARENT_ID CHILDER_ID LEVEL CONNECT_BY_ISLEAF 1 91 6 1 0 2 96 6 8 2 0 3 97 8 3 3 1 4 98 8 4 3 1 5 92 6 10 2 0 6 99 10 7 3 1 7 93 10 9 3 0 8 94 9 1 4 1 9 95 9 2 4 1观察倒数两列的值,再与上面的树进行比较
7.显示节点的遍历路径 sys_connect_by_path(field,string)
select id , parent_id , childer_id , substring(sys_connect_by_path(childer_id, '->'),3) AS PATH from DG start with childer_id = 6 connect by parent_id = prior childer_id; ID PARENT_ID CHILDER_ID PATH 1 91 6 6 2 96 6 8 6->8 3 97 8 3 6->8->3 4 98 8 4 6->8->4 5 92 6 10 6->10 6 99 10 7 6->10->7 7 93 10 9 6->10->9 8 94 9 1 6->10->9->1 9 95 9 2 6->10->9->2转载于:https://www.cnblogs.com/jinxiuze/p/7979842.html
相关资源:DirectX修复工具V4.0增强版