当前位置:Gxlcms > 数据库问题 > Sql递归查询

Sql递归查询

时间:2021-07-01 10:21:17 帮助过:5人阅读

Sql递归查询*/ /* 实际就是把所有树的节点查找出来 Oracle的一个表中也可以保存树形结构信息,用start with...connect by等关键字 eg:创建表并插入数据 */ Create table Tree(son char(10),father char(10)); insert into tree (SON, FATHER) values (孙子1, 儿子); insert into tree (SON, FATHER) values (孙子2, 儿子); insert into tree (SON, FATHER) values (儿子, 父亲); insert into tree (SON, FATHER) values (父亲, 祖父); /* son father 孙子1 儿子 孙子2 儿子 儿子 父亲 父亲 祖父 数据结构是: 祖父 | 父亲 | 儿子 / 孙子1 孙子2 */ --查询以祖父为根节点的所有节点值 SELECT son from Tree START WITH father=祖父 CONNECT BY PRIOR son=father /* START WITH后的内容可以看成一个WHERE的限制条件,其中START WITH 是指定树的根 ,还可以指定多个根,比如father in (‘祖父‘,‘父亲‘); CONNECTION BY PRIOR son=father相当于表明在递归过程中,查找到的树种其他节点接着 又作为根结点,然后继续递归。 只要记住 CONNECTION BY PRIOR那一行,要查询的列名放在前,根列名放等号后 */ --例: --树形菜单结构 CREATE TABLE tb_menu( id number(10) not null,--主键id title varchar(50),--标题 parent number(10) --父菜单id ); --父菜单数据 insert into tb_menu(id,title,parent) values(1,父菜单1,0); insert into tb_menu(id,title,parent) values(2,父菜单2,0); insert into tb_menu(id,title,parent) values(3,父菜单3,0); insert into tb_menu(id,title,parent) values(4,父菜单4,0); insert into tb_menu(id,title,parent) values(5,父菜单5,0); --一级子菜单 insert into tb_menu(id,title,parent) values(6,一级子菜单6_1,1); insert into tb_menu(id,title,parent) values(7,一级子菜单7_1,1); insert into tb_menu(id,title,parent) values(8,一级子菜单8_1,1); insert into tb_menu(id,title,parent) values(9,一级子菜单9_2,2); insert into tb_menu(id,title,parent) values(10,一级子菜单10_2,2); insert into tb_menu(id,title,parent) values(11,一级子菜单11_2,2); insert into tb_menu(id,title,parent) values(12,一级子菜单12_3,3); insert into tb_menu(id,title,parent) values(13,一级子菜单13_3,3); insert into tb_menu(id,title,parent) values(14,一级子菜单14_3,3); insert into tb_menu(id,title,parent) values(15,一级子菜单15_4,4); insert into tb_menu(id,title,parent) values(16,一级子菜单16_4,4); insert into tb_menu(id,title,parent) values(17,一级子菜单17_4,4); insert into tb_menu(id,title,parent) values(18,一级子菜单18_5,5); insert into tb_menu(id,title,parent) values(19,一级子菜单19_5,5); insert into tb_menu(id,title,parent) values(20,一级子菜单20_5,5); --二级子菜单 insert into tb_menu(id,title,parent) values(21,二级子菜单21_6,6); insert into tb_menu(id,title,parent) values(22,二级子菜单22_6,6); insert into tb_menu(id,title,parent) values(23,二级子菜单23_7,7); insert into tb_menu(id,title,parent) values(24,二级子菜单24_7,7); insert into tb_menu(id,title,parent) values(25,二级子菜单25_8,8); insert into tb_menu(id,title,parent) values(26,二级子菜单26_9,9); insert into tb_menu(id,title,parent) values(27,二级子菜单27_10,10); insert into tb_menu(id,title,parent) values(28,二级子菜单28_11,11); insert into tb_menu(id,title,parent) values(29,二级子菜单29_12,12); insert into tb_menu(id,title,parent) values(30,二级子菜单30_13,13); insert into tb_menu(id,title,parent) values(31,二级子菜单31_14,14); insert into tb_menu(id,title,parent) values(32,二级子菜单32_15,15); insert into tb_menu(id,title,parent) values(33,二级子菜单33_16,16); insert into tb_menu(id,title,parent) values(34,二级子菜单34_17,17); insert into tb_menu(id,title,parent) values(35,二级子菜单35_18,18); insert into tb_menu(id,title,parent) values(36,二级子菜单36_19,19); insert into tb_menu(id,title,parent) values(37,二级子菜单37_20,20); --三级子菜单 insert into tb_menu(id,title,parent) values(38,三级子菜单38_21,21); insert into tb_menu(id,title,parent) values(39,三级子菜单39_22,22); insert into tb_menu(id,title,parent) values(40,三级子菜单40_23,23); insert into tb_menu(id,title,parent) values(41,三级子菜单41_24,24); insert into tb_menu(id,title,parent) values(42,三级子菜单42_25,25); insert into tb_menu(id,title,parent) values(43,三级子菜单43_26,26); insert into tb_menu(id,title,parent) values(44,三级子菜单44_27,27); insert into tb_menu(id,title,parent) values(45,三级子菜单45_28,28); insert into tb_menu(id,title,parent) values(46,三级子菜单46_28,28); insert into tb_menu(id,title,parent) values(47,三级子菜单47_29,29); insert into tb_menu(id,title,parent) values(48,三级子菜单48_30,30); insert into tb_menu(id,title,parent) values(49,三级子菜单49_31,31); insert into tb_menu(id,title,parent) values(50,三级子菜单50_31,31); /* 数据结构: 父菜单1 | / 一级子菜单1_6 ... ... / 二级子菜单21_6... ... / 三级子菜单38_21... ... ... */ --①查询表中所有父菜单 select * from tb_menu m where m.parent=0; --②查询表中所有一级子菜单(即数据结构中的直属子节点) select * from tb_menu m where m.parent=1; --③查询父菜单1的所有子孙 select * from tb_menu m start with m.id=1 connect by PRIOR m.id=m.parent /* 这个SQL语句的等价写法: select * from tb_menu m start with m.id=1 connect by m.parent=PRIOR m.id 可以记做: prior放在那里,就找谁,即放在id前,即为找id的所有子孙后代 */ --④查询一个节点的直属父节点(用不到树形查询) select c.id, c.title, p.id as 父节点id , p.title as 父节点名称 from tb_menu c, tb_menu p where c.parent=p.id and c.id=6 --⑤查询一个节点的所有父节点,即父亲节点,祖先节点(需要使用树形查询) select * from tb_menu m start with m.id=50 connect by PRIOR m.parent=m.id /*引入level和lpad实现分层显示*/ select level, lpad( , 2 * level - 1) || m.id from tb_menu m start with m.id = 1 connect by prior m.id = m.parent /* prior就是表示上一条记录的意思,即prior m.parent=m.id就是表示上一条记录的父id是本条记录的id 也就是本条记录是上一条记录的父亲,那么就是在查询所有记录的父节点/祖先节点,反之。 */ --⑥查询一个节点(一级子菜单6_1)的兄弟节点(亲兄弟) select * from tb_menu m where exists (select * from tb_menu m2 where m.parent=m2.parent and m2.id=6) /*从SQL语句理解就是:查询表的数据,数据符合条件,在m2只要存在m.parent=m2.parent的数据,即取出*/ --⑦查询一个节点所有同级的节点(族兄弟) with tmp as( select a.* ,level leaf from tb_menu a start with a.parent=0 connect by prior a.id=a.parent ) select * from tmp where leaf=(select leaf from tmp where id=50) /*在SQL语句⑦中使用了level来标识每个节点在表中的级别【level表示递归的层次,即查询的深度】,使用了with语法来虚拟出了一张带有级别的临时表*/ /*=========================【补充】with语法:================================== 要求Oracle版本Oracle 9i及以上 其实就是把一些重复用到的SQL语句放在with as里面,取一个别名,后面的查询中就可以使用这个别名,对大批量的SQL 语句起到一个优化的作用。 eg1: with t1 as (select * from emp e where e.ename like ‘%N%‘) select * from t1; eg2: with t1 as (select * from emp), t2 as (select * from dept) select * from t1,t2 where t1.deptno=t2.deptno 对于union all通常使用with as提升效率 因为union all的每个执行部分可能相同,如果每个部分都执行一遍成本太高,如果使用with as短语只执行一次即可 eg3: with t1 as (select t.name as name from table1 t where t.age>20), t2 as (select s.lastname as name from table2 s where exists(select s.name from table3 p where s.id=p.id and p.id=‘a001‘)) select * from t1 union all select * from t2 =====================================================================*/ --⑧查询一个节点的父节点的亲兄弟节点 /* 1、如果当前节点为最顶级的节点,即level=1,没有父节点,不考虑 2、如果当期节点为2级节点,即level=2,那么level=1的节点就是他的父节点和父节点的兄弟节点 3、如果level是3或者3以上,那么就要查询出来其祖父节点,再判断祖父节点的下一级(即父节点)是其父节点和父节点的兄弟节点 4、将结果集union在一起 */ with tmp as ( select m.*,level lev from tb_menu m start with m.parent=0 connect by m.parent= prior m.id ) select b.* from tmp b ,(select * from tmp where id=21 and lev=2) a where b.lev=1 union all select * from tmp where parent=( select distinct x.id from tmp x,--祖父 tmp y,--父亲 (select * from tmp where id=21 and lev>2) z--儿子 where y.id=z.parent and x.id=y.parent ) --⑨查询一个节点的父节点的所有兄弟节点(族兄弟) with tmp as ( select m.*,level leaf from tb_menu m start with m.parent=0 connect by m.parent= prior m.id ) select * from tmp where leaf=(select leaf from tmp where id=6)-1 --⑩列出全部路径,比如省/市/区/街道/社区 /*从顶部开始*/ select sys_connect_by_path(title,/) from tb_menu m where id=50 start with parent =0 connect by parent =prior id /*从当前节点开始*/ select sys_connect_by_path(title,/) from tb_menu m start with id=50 connect by prior parent =id /* sys_connect_by_path函数是从start with开始的地方遍历,并记录下遍历到的节点。start with开始的地方被视为根节点, 将遍历到的路径根据函数中的分隔符组成一个新的字符串! */ /* 还有一些功能同样很强大的函数 connect_by_root函数用在列前,记录的是当前节点的根节点的内容 select connect_by_root title,tb_menu.* from tb_menu start with id=50 connect by prior parent=id connect_by_isleaf函数用来判断当前节点是否包含下级节点,如果包含下级节点说明不是叶子节点(即没有子节点的节点,不管在第几级,只要没有子节点就是叶子节点),返回0, 否则不包含,返回1 select connect_by_isleaf,tb_menu.* from tb_menu start with parent=0 connect by parent =prior id; */

Sql递归查询

标签:rac   union all   class   sel   显示   数据   三级   number   distinct   

人气教程排行