Oracle:递归树形结构查询功能

概要

树状结构通常由根节点、父节点(PID)、子节点(ID)和叶节点组成。

查询语法

SELECT [LEVEL],*
FROM table_name
START WITH 条件1
CONNECT BY PRIOR 条件2
WHERE 条件3
ORDER BY 排序字段
说明:LEVEL—伪列,用于表示树的层次(用于查询结果所在层次,根节点的层次为1)
   条件1—根节点的限定条件,当然也可以放宽权限,以获得多个根节点,也就是获取多个树(即:start with 后面的条件表示递归从哪里开始。)
   条件2—连接条件,目的就是给出父子之间的关系是什么,根据这个关系进行递归查询(即:递归时前后两条数据是以条件2来建立联系的)
   条件3—过滤条件,对所有返回的记录进行过滤。
   排序字段—对所有返回记录进行排序

prior使用

prior的位置决定了递归时的具体关系或者说是决定了查询时的检索顺序,prior 字段1=字段2 可以理解为当前节点的字段1等于下一个节点的字段2。

两种写法:

connect by prior PID=ID 表示采用 自上而下的搜索方式(先找父节点然后找子节点)
connect by PID=prior ID 表示采用 自下而上的搜索方式(先找叶子节点然后找父节点)

举例

语法:

select
from 表名 t
where 过滤条件
start with t.PID=xx --开始根节点
connect by prior t.ID=t.PID
SELECT t.JGBH
  FROM GG_JGBH t
 where SYBZ = 1
 START WITH t.SJJG = (select SJJG from GG_JGBH where JGBH = '0001')
CONNECT BY PRIOR t.JGBH = t.SJJG

但上速查询的内容不包括“开始根节点”所对应的数据,此时我的解决方式是使用OR来关联

select E_ADDRESS.*, (select jgmc from gg_jgbh where jgbh = account) jgmc
  from E_ADDRESS
 where ACCOUNT = (select SJJG from GG_JGBH where JGBH = '0001')
    or ACCOUNT in
       (SELECT t.JGBH
          FROM GG_JGBH t
         where SYBZ = 1
         START WITH t.SJJG = (select SJJG from GG_JGBH where JGBH = '0001')
        CONNECT BY PRIOR t.JGBH = t.SJJG)

实例代码

1.查询某节点下所有后代节点(包括各级父节点)

// 查询id为101的所有后代节点,包含101在内的各级父节点
select t.* from SYS_ORG t start with id = '101' connect by parent_id = prior id

2.查询某节点下所有后代节点(不包含各级父节点)

select t.*
from SYS_ORG t
where not exists (select 1 from SYS_ORG s where s.parent_id = t.id)
start with id = '101'
connect by parent_id = prior id

3.查询某节点所有父节点(所有祖宗节点,包括自己

select t.*
  from SYS_ORG t
start with id = '401000501'
connect by prior parent_id = id

4.查询某节点所有的兄弟节点(亲兄弟)

select * from SYS_ORG t
where exists (select * from SYS_ORG s where t.parent_id=s.parent_id and s.id='401000501')

5.查询某节点所有同级节点(族节点),假设不设置级别字段

这里使用两个技巧,一个是使用了level来标识每个节点在表中的级别,还有就是使用with语法模拟出了一张带有级别的临时表
with tmp as(
      select t.*, level leaf
      from SYS_ORG t
      start with t.parent_id = '0'
      connect by t.parent_id = prior t.id)
select *
      from tmp
where leaf = (select leaf from tmp where id = '401000501');

6.查询某节点的父节点及父的兄弟节点(叔伯节点)

这里查询分成以下几步。
首先,将全表都使用临时表加上级别;
其次,根据级别来判断有几种类型,以上文中举的例子来说,有三种情况:
(1)当前节点为顶级节点,即查询出来的lev值为1,那么它没有上级节点,不予考虑。
(2)当前节点为2级节点,查询出来的lev值为2,那么就只要保证lev级别为1的就是其上级节点的兄弟节点。
(3)其它情况就是3以及以上级别,那么就要选查询出来其上级的上级节点(祖父),再来判断祖父的下级节点都是属于该节点的上级节点的兄弟节点。
最后,就是使用union将查询出来的结果进行结合起来,形成结果集。
with tmp as(
    select t.*, level lev
    from SYS_ORG t
    start with t.parent_id = '0'
    connect by t.parent_id = prior t.id)
select b.*
from tmp b,(select *
            from tmp
            where id = '401000501' and lev = '2') a
where b.lev = '1'
 
union all
 
select *
from tmp
where parent_id = (select distinct x.id
                from tmp x, --祖父
                     tmp y, --父亲
                     (select *
                      from tmp
                      where id = '401000501' and lev > '2') z --儿子
                where y.id = z.parent_id and x.id = y.parent_id); 

猜你喜欢

转载自blog.csdn.net/weixin_63610637/article/details/129539674