Oracle递归详解

1、描述:

什么是递归?

古之欲明明德于天下者,先治其国;欲治其国者,先齐其家;欲齐其家者,先修其身;欲修其身者,先正其心;欲正其心者,先诚其意。

start with...connect by prior用于实现递归查询树形结构。如果不好理解proir的向上向下,就记住如果想往上遍历就把上级节点放在prior后,如果想往下遍历反之将下级节点放在prior后。简单粗暴。

2、语法:

 SELECT *
   FROM t_name
 {WHERE 条件一}
  START WITH 条件二
CONNECT BY {PRIOR PARENT=ID|PARENT=PRIOR ID} 

3、数据:

建表语句:

-- Create table
create table AREA_SHANDONG
(
  area_id     VARCHAR2(10),
  area_name   VARCHAR2(20),
  parent_id   VARCHAR2(10),
  parent_name VARCHAR2(20)
)
tablespace TS_TAB_ICRMAPP_DAT
  pctfree 10
  initrans 1
  maxtrans 255
  storage
  (
    initial 64K
    next 1M
    minextents 1
    maxextents unlimited
  );
-- Add comments to the table 
comment on table AREA_SHANDONG
  is '地区信息表-山东';
-- Add comments to the columns 
comment on column AREA_SHANDONG.area_id
  is '地区号';
comment on column AREA_SHANDONG.area_name
  is '地区名';
comment on column AREA_SHANDONG.parent_id
  is '上级地区号';
comment on column AREA_SHANDONG.parent_name
  is '上级地区名称';

数据:

prompt Importing table area_shandong...
set feedback off
set define off
insert into area_shandong (AREA_ID, AREA_NAME, PARENT_ID, PARENT_NAME)
values ('1000', '山东省', null, null);

insert into area_shandong (AREA_ID, AREA_NAME, PARENT_ID, PARENT_NAME)
values ('1100', '济南市', '1000', '山东省');

insert into area_shandong (AREA_ID, AREA_NAME, PARENT_ID, PARENT_NAME)
values ('1200', '青岛市', '1000', '山东省');

insert into area_shandong (AREA_ID, AREA_NAME, PARENT_ID, PARENT_NAME)
values ('1210', '市南区', '1200', '青岛市');

insert into area_shandong (AREA_ID, AREA_NAME, PARENT_ID, PARENT_NAME)
values ('1220', '市北区', '1200', '青岛市');

insert into area_shandong (AREA_ID, AREA_NAME, PARENT_ID, PARENT_NAME)
values ('1230', '崂山区', '1200', '青岛市');

insert into area_shandong (AREA_ID, AREA_NAME, PARENT_ID, PARENT_NAME)
values ('1240', '李村区', '1200', '青岛市');

insert into area_shandong (AREA_ID, AREA_NAME, PARENT_ID, PARENT_NAME)
values ('1250', '城阳区', '1200', '青岛市');

insert into area_shandong (AREA_ID, AREA_NAME, PARENT_ID, PARENT_NAME)
values ('1260', '黄岛区', '1200', '青岛市');

insert into area_shandong (AREA_ID, AREA_NAME, PARENT_ID, PARENT_NAME)
values ('1300', '烟台市', '1000', '山东省');

insert into area_shandong (AREA_ID, AREA_NAME, PARENT_ID, PARENT_NAME)
values ('1310', '莱山区', '1300', '烟台市');

insert into area_shandong (AREA_ID, AREA_NAME, PARENT_ID, PARENT_NAME)
values ('1320', '福山区', '1300', '烟台市');

insert into area_shandong (AREA_ID, AREA_NAME, PARENT_ID, PARENT_NAME)
values ('1330', '牟平区', '1300', '烟台市');

insert into area_shandong (AREA_ID, AREA_NAME, PARENT_ID, PARENT_NAME)
values ('1340', '开发区', '1300', '烟台市');

insert into area_shandong (AREA_ID, AREA_NAME, PARENT_ID, PARENT_NAME)
values ('1350', '高新区', '1300', '烟台市');

insert into area_shandong (AREA_ID, AREA_NAME, PARENT_ID, PARENT_NAME)
values ('1360', '长岛县', '1300', '烟台市');

insert into area_shandong (AREA_ID, AREA_NAME, PARENT_ID, PARENT_NAME)
values ('1370', '海阳市', '1300', '烟台市');

insert into area_shandong (AREA_ID, AREA_NAME, PARENT_ID, PARENT_NAME)
values ('1371', '东村街道', '1370', '海阳市');

insert into area_shandong (AREA_ID, AREA_NAME, PARENT_ID, PARENT_NAME)
values ('1372', '方园街道', '1370', '海阳市');

insert into area_shandong (AREA_ID, AREA_NAME, PARENT_ID, PARENT_NAME)
values ('1373', '凤城街道', '1370', '海阳市');

insert into area_shandong (AREA_ID, AREA_NAME, PARENT_ID, PARENT_NAME)
values ('1374', '龙山街道', '1370', '海阳市');

insert into area_shandong (AREA_ID, AREA_NAME, PARENT_ID, PARENT_NAME)
values ('1375', '行村镇', '1370', '海阳市');

insert into area_shandong (AREA_ID, AREA_NAME, PARENT_ID, PARENT_NAME)
values ('1376', '新安镇', '1370', '海阳市');

insert into area_shandong (AREA_ID, AREA_NAME, PARENT_ID, PARENT_NAME)
values ('1377', '小集镇', '1370', '海阳市');

insert into area_shandong (AREA_ID, AREA_NAME, PARENT_ID, PARENT_NAME)
values ('1378', '徐家店镇', '1370', '海阳市');

insert into area_shandong (AREA_ID, AREA_NAME, PARENT_ID, PARENT_NAME)
values ('1379', '李典镇', '1370', '海阳市');

insert into area_shandong (AREA_ID, AREA_NAME, PARENT_ID, PARENT_NAME)
values ('1400', '淄博市', '1000', '山东省');

insert into area_shandong (AREA_ID, AREA_NAME, PARENT_ID, PARENT_NAME)
values ('1500', '威海市', '1000', '山东省');

insert into area_shandong (AREA_ID, AREA_NAME, PARENT_ID, PARENT_NAME)
values ('1600', '东营市', '1000', '山东省');

insert into area_shandong (AREA_ID, AREA_NAME, PARENT_ID, PARENT_NAME)
values ('1700', '潍坊市', '1000', '山东省');

insert into area_shandong (AREA_ID, AREA_NAME, PARENT_ID, PARENT_NAME)
values ('1800', '日照市', '1000', '山东省');

insert into area_shandong (AREA_ID, AREA_NAME, PARENT_ID, PARENT_NAME)
values ('1900', '德州市', '1000', '山东省');

prompt Done.

4、案例:

1、查询1000节点儿子节点

SQL> SELECT *
  2    FROM area_shandong
  3   WHERE parent_id = '1000' ;
AREA_ID    AREA_NAME            PARENT_ID  PARENT_NAME
---------- -------------------- ---------- --------------------
1100       济南市               1000       山东省
1200       青岛市               1000       山东省
1300       烟台市               1000       山东省
1400       淄博市               1000       山东省
1500       威海市               1000       山东省
1600       东营市               1000       山东省
1700       潍坊市               1000       山东省
1800       日照市               1000       山东省
1900       德州市               1000       山东省
9 rows selected

2、查询1200节点所有子节点

SQL>  SELECT *
  2     FROM area_shandong
  3    START WITH parent_id='1200'
  4  CONNECT BY PRIOR area_id = parent_id;
AREA_ID    AREA_NAME            PARENT_ID  PARENT_NAME
---------- -------------------- ---------- --------------------
1210       市南区               1200       青岛市
1220       市北区               1200       青岛市
1230       崂山区               1200       青岛市
1240       李村区               1200       青岛市
1250       城阳区               1200       青岛市
1260       黄岛区               1200       青岛市
6 rows selected

3、查找1260节点所有上级节点

SQL>  SELECT * from area_shandong start with area_id='1260' connect by prior parent_id=area_id;
AREA_ID    AREA_NAME            PARENT_ID  PARENT_NAME
---------- -------------------- ---------- --------------------
1260       黄岛区               1200       青岛市
1200       青岛市               1000       山东省
1000       山东省 

4、查询1260节点的簇兄弟(在同一层级)

SQL> with tmp as(
  2   select a.*, level leaf
  3   from area_shandong a
  4   start with a.parent_id is null
  5   connect by a.parent_id = prior a.area_id)
  6   select *
  7   from tmp
  8   where leaf = (select leaf from tmp where area_id =1260 );
AREA_ID    AREA_NAME            PARENT_ID  PARENT_NAME                LEAF
---------- -------------------- ---------- -------------------- ----------
1210       市南区               1200       青岛市                        3
1220       市北区               1200       青岛市                        3
1230       崂山区               1200       青岛市                        3
1240       李村区               1200       青岛市                        3
1250       城阳区               1200       青岛市                        3
1260       黄岛区               1200       青岛市                        3
1310       莱山区               1300       烟台市                        3
1320       福山区               1300       烟台市                        3
1330       牟平区               1300       烟台市                        3
1340       开发区               1300       烟台市                        3
1350       高新区               1300       烟台市                        3
1360       长岛县               1300       烟台市                        3
1370       海阳市               1300       烟台市                        3
13 rows selected

以下两个案例可以额外学习一下,另外还有一个函数个人不常用就不写了,有兴趣可以自己去查一下。

5、查询递归路径

SQL> select area_id, area_name, parent_id,
  2   substr(sys_connect_by_path(area_name,'->'),3) path
  3   from area_shandong
  4   start with area_id='1000'
  5   connect by prior area_id=parent_id;
AREA_ID    AREA_NAME            PARENT_ID  PATH
---------- -------------------- ---------- --------------------------------------------------------------------------------
1000       山东省                          山东省
1100       济南市               1000       山东省->济南市
1200       青岛市               1000       山东省->青岛市
1210       市南区               1200       山东省->青岛市->市南区
1220       市北区               1200       山东省->青岛市->市北区
1230       崂山区               1200       山东省->青岛市->崂山区
1240       李村区               1200       山东省->青岛市->李村区
1250       城阳区               1200       山东省->青岛市->城阳区
1260       黄岛区               1200       山东省->青岛市->黄岛区
1300       烟台市               1000       山东省->烟台市
1310       莱山区               1300       山东省->烟台市->莱山区
1320       福山区               1300       山东省->烟台市->福山区
1330       牟平区               1300       山东省->烟台市->牟平区
1340       开发区               1300       山东省->烟台市->开发区
1350       高新区               1300       山东省->烟台市->高新区
1360       长岛县               1300       山东省->烟台市->长岛县
1370       海阳市               1300       山东省->烟台市->海阳市
1371       东村街道             1370       山东省->烟台市->海阳市->东村街道
1372       方园街道             1370       山东省->烟台市->海阳市->方园街道
1373       凤城街道             1370       山东省->烟台市->海阳市->凤城街道
AREA_ID    AREA_NAME            PARENT_ID  PATH
---------- -------------------- ---------- --------------------------------------------------------------------------------
1374       龙山街道             1370       山东省->烟台市->海阳市->龙山街道
1375       行村镇               1370       山东省->烟台市->海阳市->行村镇
1376       新安镇               1370       山东省->烟台市->海阳市->新安镇
1377       小集镇               1370       山东省->烟台市->海阳市->小集镇
1378       徐家店镇             1370       山东省->烟台市->海阳市->徐家店镇
1379       李典镇               1370       山东省->烟台市->海阳市->李典镇
1400       淄博市               1000       山东省->淄博市
1500       威海市               1000       山东省->威海市
1600       东营市               1000       山东省->东营市
1700       潍坊市               1000       山东省->潍坊市
1800       日照市               1000       山东省->日照市
1900       德州市               1000       山东省->德州市
32 rows selected

6、查询节点是否为叶节点(叶节点为1,非叶节点为0)

SQL>  select m.*, connect_by_isleaf leaf
  2   from area_shandong m
  3   start with parent_id is null
  4   connect by parent_id = prior area_id;
AREA_ID    AREA_NAME            PARENT_ID  PARENT_NAME                LEAF
---------- -------------------- ---------- -------------------- ----------
1000       山东省                                                        0
1100       济南市               1000       山东省                        1
1200       青岛市               1000       山东省                        0
1210       市南区               1200       青岛市                        1
1220       市北区               1200       青岛市                        1
1230       崂山区               1200       青岛市                        1
1240       李村区               1200       青岛市                        1
1250       城阳区               1200       青岛市                        1
1260       黄岛区               1200       青岛市                        1
1300       烟台市               1000       山东省                        0
1310       莱山区               1300       烟台市                        1
1320       福山区               1300       烟台市                        1
1330       牟平区               1300       烟台市                        1
1340       开发区               1300       烟台市                        1
1350       高新区               1300       烟台市                        1
1360       长岛县               1300       烟台市                        1
1370       海阳市               1300       烟台市                        0
1371       东村街道             1370       海阳市                        1
1372       方园街道             1370       海阳市                        1
1373       凤城街道             1370       海阳市                        1
AREA_ID    AREA_NAME            PARENT_ID  PARENT_NAME                LEAF
---------- -------------------- ---------- -------------------- ----------
1374       龙山街道             1370       海阳市                        1
1375       行村镇               1370       海阳市                        1
1376       新安镇               1370       海阳市                        1
1377       小集镇               1370       海阳市                        1
1378       徐家店镇             1370       海阳市                        1
1379       李典镇               1370       海阳市                        1
1400       淄博市               1000       山东省                        1
1500       威海市               1000       山东省                        1
1600       东营市               1000       山东省                        1
1700       潍坊市               1000       山东省                        1
1800       日照市               1000       山东省                        1
1900       德州市               1000       山东省                        1
32 rows selected
  • 5
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Oracle中的递归可以通过使用`WITH`子句和`CONNECT BY`子句来实现。这种递归查询方式被称为“递归公共表达式(Recursive Common Table Expression)”。 下面是一个简单的递归查询的例子,假设我们有一个员工表`EMP`,其中有一个字段`MGR`表示员工的上级经理: ``` EMPNO ENAME JOB MGR 1 John Manager NULL 2 Bob Clerk 1 3 Alice Clerk 1 4 Tom Analyst 2 5 Mary Analyst 3 6 Jack Salesman 1 ``` 我们可以使用递归查询来查找每个员工的所有下属,包括直接下属和间接下属。下面是一个使用递归查询的示例: ``` WITH emp_tree AS ( SELECT empno, ename, job, mgr, 0 AS level FROM emp WHERE mgr IS NULL UNION ALL SELECT emp.empno, emp.ename, emp.job, emp.mgr, emp_tree.level + 1 FROM emp_tree JOIN emp ON emp.mgr = emp_tree.empno ) SELECT empno, ename, job, level FROM emp_tree ORDER BY level, empno; ``` 在上面的查询中,我们首先定义了一个递归公共表达式`emp_tree`,它包含了所有顶级经理的信息。然后我们使用`UNION ALL`运算符将顶级经理和他们的直接下属组合在一起,并将`level`设置为0。接下来,我们使用`JOIN`运算符将每个下属与其直接上级经理连接起来,并将`level`设置为上级经理的`level + 1`。最后,我们从递归公共表达式`emp_tree`中选择所有下属的信息,并按照`level`和`empno`排序。 执行以上查询的结果如下: ``` EMPNO ENAME JOB LEVEL ---- ------ --------- ----- 1 John Manager 0 2 Bob Clerk 1 3 Alice Clerk 1 6 Jack Salesman 1 4 Tom Analyst 2 5 Mary Analyst 2 ``` 在这个结果中,我们可以看到每个员工的编号、姓名、职位和级别。其中,顶级经理的级别为0,直接下属的级别为1,间接下属的级别为2。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

D2cOneluo

万一有大佬给个打赏呢,对不对。

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值