Sql递归查询

/*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;
        */
时间: 2024-10-24 17:32:21

Sql递归查询的相关文章

【转】sql递归查询问题

原文链接地址http://www.cnblogs.com/sweting/archive/2009/06/08/1498483.html 在工作中遇到一个问题,是需要sql递归查询的.不懂,于是到csdn上去问,那里的效率真是非常高,我以前也没在上面问过问题. 问题描述: 我有一个表结构如下:id upperid1     23     24     15     3 具体层次不知道,我想用递归sql语句把所有属于某个upperid的数据,包括它的子树,都读出去,请问应该子怎么写?      比

关于Oracle、SqlServer 的sql递归查询

递归查询所有子节点 oracle SELECT * FROM hrmdepartment              START WITH  id=22              CONNECT BY PRIOR id=supdepid sqlserver with result_table as               (                  select a.id,a.lastname,a.managerid from hrmresource a where id=321 

关于SQL递归查询在不同数据库中的实现方法

比如表结构数据如下: Table:Tree ID Name ParentId 1 一级  0 2  二级 1 3  三级 2 4 四级 3 SQL SERVER 2005查询方法: //上查 with tmpTree as ( select * from Tree where Id=2 union all select p.* from tmpTree inner join Tree p on p.Id=tmpTree.ParentId ) select * from tmpTree //下查

sql 递归查询所有的下级

--> 生成测试数据表: [tb] IF OBJECT_ID('[Users]') IS NOT NULL     DROP TABLE [Users] GO CREATE TABLE [Users] ([userid] [int],[username] [nvarchar](10),[parentUserId] [int],[parentUserName] [nvarchar](10)) INSERT INTO [Users] SELECT '1','admin','0',NULL UNION

SQL递归查询(with cte as) 物料分解

需求 最近在做一个MRP的项目,需要根据生产下达的计划从原始无聊表中分解出成品所需要的原材料和数量. 参考 http://www.cnblogs.com/xqhppt/archive/2011/02/15/1955366.html http://www.cnblogs.com/guoysh1987/archive/2011/12/23/2299379.html 代码实现 SQL数据表结构 CREATE TABLE [dbo].[cProduction]( [ID] [int] IDENTITY(

SQL递归查询(with cte as)

http://www.cnblogs.com/xqhppt/archive/2011/02/15/1955366.html 2011-02-15 16:41 by 忧忧夏天, 2415 阅读, 0 评论, 收藏, 编辑 with cte as(select Id,Pid,DeptName,0as lvl from Departmentwhere Id =2unionallselect d.Id,d.Pid,d.DeptName,lvl+1from cte c innerjoin Departme

sql递归查询子级

WITH T(emp_no, name, dept_no, the_level, path,path1,manager_id) AS( SELECT emp_no, name, dept_no ,1 AS the_level ,'\'||name path ,'\'||manager_id path1 ,manager_id FROM BASE_HR_EMP where emp_no='10002241' UNION ALL SELECT e.emp_no, e.name, e.dept_no

SQL 递归查询

;WITH T AS( SELECT Id FROM tb AS A WHERE --NOT EXISTS(SELECT * FROM tb WHERE Id = A.ParentId ) AND --加这句条件,就排除自己 A.Id='5801CB7F-06DB-46A7-BA97-F0C7CB5D3ADA' UNION ALL SELECT A.Id FROM [tb] AS A JOIN T AS B ON A.ParentId = B.Id )SELECT Id FROM T ; 原文地

postgre sql递归查询

WITH  RECURSIVE  r  AS (SELECT * FROM [表] WHERE id = xxxunion ALLSELECT [表].* FROM [表], r WHERE [表].id = r.parent_id)SELECT * FROM r ORDER BY id; 递归向上查询数据 原文地址:https://www.cnblogs.com/snail90/p/9972447.html