Oracle 递归
当对象存在父节点、子节点时,通过特定的方式获取父节点、子节点数据构建树状结构或其它形式结构时,通常都会使用递归,如:一个公司有多个部门、每个部门下可能有多个小部门,小部门下面又有组….为了数据容易管理和维护,通过构建合适的表结构存储这些数据,以下示例以省市县为例学习了解递归:
1.创建存储省市县数据表:
1: create table tb_distree
2: (
3: id number,
4: name varchar2(300),
5: pid number
6: )
7: /
8: remark 添加主外键
9: alter table tb_distree add (
10: constraints pk_id primary key(id),
11: constraints fk_pid foreign key(pid) references tb_distree(id)
12: )
13: /
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
2.初始化数据:
1: insert into tb_distree(id,name) values(1,'云南省');
2: insert into tb_distree(id,name,pid) values(2,'昆明市',1);
3: insert into tb_distree(id,name,pid) values(3,'临沧市',1);
4: insert into tb_distree(id,name,pid) values(4,'丽江市',1);
5: insert into tb_distree(id,name,pid) values(5,'云县',3);
6: insert into tb_distree(id,name,pid) values(6,'凤庆',3);
7: insert into tb_distree(id,name,pid) values(7,'幸福',3);
8: insert into tb_distree(id,name,pid) values(8,'盘龙区',2);
9: insert into tb_distree(id,name,pid) values(9,'五华区',2);
10: insert into tb_distree(id,name,pid) values(10,'西山区',2);
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
3.递归查询语法:
1: select column... from table_name
2: where .... 过滤条件
3: start with ... 递归开始点
4: connect by prior .... 优先级
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
4.递归查询数据:
4.1 从父节点开始查询出所有父节点和子节点:
SQL> select id,name,pid from tb_distree start with pid is null connect by prior id=pid;
ID NAME PID
---------- ------------ ----------
1 云南省
2 昆明市 1
8 盘龙区 2
9 五华区 2
10 西山区 2
3 临沧市 1
5 云县 3
6 凤庆 3
7 幸福 3
4 丽江市 1
10 rows selected.
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
4.2 查询某个节点的父节点:
SQL> select id,name,pid from tb_distree start with name='云县' connect by prior pid=id;
ID NAME PID
---------- ------------ ----------
5 云县 3
3 临沧市 1
1 云南省
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
在上例中"云县"属于"临沧市","临沧市"属于"云南省";对于从父节点递归到子节点,优先级条件为子节点id等于父节点id;对于从子节点到父节点递归,方向刚好相反;
4.3 通过层次查询出父节点和某个子节点:
SQL> select id,name,pid,level from tb_distree where level in(1,2) start with pid is null connect by prior id=pid;
ID NAME PID LEVEL
---------- ------------ ---------- ----------
1 云南省 1
2 昆明市 1 2
3 临沧市 1 2
4 丽江市 1 2
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
层次也很重要,某些时候要修改某个节点父节点或子节点时会很有用;
5. 递归查询效率:
SQL>select/*+ selectDG1 */ id,name,pid from tb_distree start with pid is null connect by prior id=pid;
SQL> select sql_id,sql_text from v$sql where sql_text like '%selectDG1%' ;
SQL_ID SQL_TEXT
--------------- --------------------------------------------------
2wnu324ga4n0y select sql_id,sql_text from v$sql where sql_text l
ike '%selectDG1%'
d4g89bucsbvzd select/*+ selectDG1 */ id,name,pid from tb_distree
start with pid is null connect by prior id=pid
SQL>select * from table(dbms_xplan.display_cursor('d4g89bucsbvzd',null,'advanced allstats last peeked_binds'));
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------
SQL_ID d4g89bucsbvzd, child number 0
-------------------------------------
select/*+ selectDG1 */ id,name,pid from tb_distree start with pid is
null connect by prior id=pid
Plan hash value: 1466399788
------------------------------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows |E-Bytes| Cost (%CPU)| E-Time | A-Rows | A-Time | Buffers |
------------------------------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | | 18 (100)| | 10 |00:00:00.01 | 22 |
PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------------------------------
|* 1 | CONNECT BY NO FILTERING WITH START-WITH| | 1 | | | | | 10 |00:00:00.01 | 22 |
| 2 | TABLE ACCESS FULL | TB_DISTREE | 1 | 10 | 1780 | 17 (0)| 00:00:01 | 10 |00:00:00.01 | 22 |
------------------------------------------------------------------------------------------------------------------------------------------------
Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------
1 - SEL$1
2 - SEL$2 / TB_DISTREE@SEL$2
Outline Data
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------------------------------------------------------------------
/*+
BEGIN_OUTLINE_DATA
IGNORE_OPTIM_EMBEDDED_HINTS
OPTIMIZER_FEATURES_ENABLE('11.2.0.3')
DB_VERSION('11.2.0.3')
ALL_ROWS
OUTLINE_LEAF(@"SEL$2")
OUTLINE_LEAF(@"SEL$3")
OUTLINE_LEAF(@"SEL$4")
PLAN_TABLE_OUTPUT
---------------------------------------------------------------------------------------------------------------------------------------------------
OUTLINE_LEAF(@"SET$1")
OUTLINE_LEAF(@"SEL$1")
NO_ACCESS(@"SEL$1" "connect$_by$_work$_set$_006"@"SEL$1")
NO_CONNECT_BY_FILTERING(@"SEL$1")
CONNECT_BY_COMBINE_SW(@"SEL$1")
FULL(@"SEL$4" "TB_DISTREE"@"SEL$4")
FULL(@"SEL$3" "connect$_by$_pump$_002"@"SEL$3")
FULL(@"SEL$3" "TB_DISTREE"@"SEL$3")
LEADING(@"SEL$3" "connect$_by$_pump$_002"@"SEL$3" "TB_DISTREE"@"SEL$3")
USE_HASH(@"SEL$3" "TB_DISTREE"@"SEL$3")
FULL(@"SEL$2" "TB_DISTREE"@"SEL$2")
PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------------------------------------------------
END_OUTLINE_DATA
*/
Predicate Information (identified by operation id):
---------------------------------------------------
1 - access("PID"=PRIOR NULL)
filter("PID" IS NULL)
10046 trace:
Rows (1st) Rows (avg) Rows (max) Row Source Operation
675 ---------- ---------- ---------- ---------------------------------------------------
676 10 10 10 CONNECT BY NO FILTERING WITH START-WITH (cr=22 pr=0 pw=0 time=269 us)
677 10 10 10 TABLE ACCESS FULL TB_DISTREE (cr=22 pr=0 pw=0 time=118 us cost=17 size=1780 card=10)
678
679
680 Elapsed times include waiting on following events:
681 Event waited on Times Max. Wait Total Waited
682 ---------------------------------------- Waited ---------- ------------
683 row cache lock 3 0.00 0.00
684 Disk file operations I/O 1 0.00 0.00
685 db file sequential read 3 0.03 0.04
686 SQL*Net message to client 2 0.00 0.00
687 SQL*Net message from client 2 0.00 0.00
688 ********************************************************************************
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
在递归表上创建索引是没有用的,都必须进行全表扫描,当然通常这样的表也不会很大,如果数据量的确很大,建议将表中的节点拆分成多个表提高效率;
Oracle 递归的更多相关文章
- Oracle 递归的写法(start with) 以及where条件作用域
先转一个讲Oracle递归讲得非常透彻的文章: http://blog.csdn.net/weiwenhp/article/details/8218091 前言:嗯,这也是一个前人挖坑,后人来填的故事 ...
- oracle 递归应用(挺复杂的)
最近做数据过滤觉得很有必要记录下整个过程,说不定下次就不知道了. 废话不多说开始: 表结构: 企业表(自关联,采用树的形式记录分子公司) 区域表(自关联,采用树的形式记录省/市/县/乡,数据量大) 公 ...
- oracle 递归和connect by【转】
oracle递归查询(单表包含多级上下级关系) http://www.cnblogs.com/walk-the-Line/p/4882866.html -- 查找所有第一层(包括)下的所有子节点 -- ...
- oracle递归层级查询 start with connect by prior
递归层级查询:start with connect by prior 以部门表作为解析 表结构:dept{id:'主键',name:'部门名称',parent_id:'父亲id'} select * ...
- Oracle递归sql笔记
查询一个机构下所辖机构: select * from t00_organ t start with t.organkey=#uporgankey# connect by prior t.organke ...
- Oracle递归 start with...connect by...prior
prior一侧是父节点 另一侧是子节点 --查询region_id等于4519的节点下面的所有子节点 查找出给定节点的所有子节点 SELECT sr.* FROM spc_region sr wher ...
- Oracle递归操作
需求:找出代理商中没有挂商家的代理商 简单SQL如下: select * from t_proxy tp where tp.id not in (SELECT tp.id as p_id FROM t ...
- [oracle] 递归追溯完整部门名称 函数
create or replace function fn_DeptWholeName2(objectid in number) return nvarchar2 is wholename nvarc ...
- oracle 分页(rownum的理解) 以及 树节点的查询
1:什么是rownum, rownum的生成, rownum相关的符号操作 Rownum是oracle生成结果集时得到的一个伪列, 按照读出行的顺序, 第一条rownum=1, 第二条=2. 对于 O ...
随机推荐
- 【转】使用JMeter对数据库做压力测试
作为一名开发人员,大多情况下都会认真的做好功能测试,但是却常常忽略了软件开发之后的压力测试,尤其是在面向大量用户同时使用的Web应用系统的开发过程,压力测试往往是不够充分的.近期我在一个求职招聘型的网 ...
- 【转】JMeter 通过 JDBC 访问 Oracle 和 MySQL
JMeter 的手册中描述了如何访问 MySQL,但是没有说明如何访问 Oracle.对于没有 Java 应用开发经验和对 Oracle 不是特别熟悉的朋友,可以参考这篇文章来简单.快速的配置好 JM ...
- Java中的强制类型转换
例如,当程序中需要将 double 型变量的值赋给一个 int 型变量,该如何实现呢? 显然,这种转换是不会自动进行的!因为 int 型的存储范围比 double 型的小.此时就需要通过强制类型转换来 ...
- JVM内存管理和问题简要分析学习
Java中我们基本上不会显式地调用分配内存的函数,分配内存和回收内存都由JVM自动完成了. 所谓物理内存就是我们通常说的RAM(随机存储器),计算机中还有一个存储单元叫做寄存器,用于存储计算单 ...
- 浅谈PHP面向对象编程(四、类常量和静态成员)
4.0 类常量和静态成员 通过上几篇博客我们了解到,类在实例化对象时,该对象中的成员只被当前对象所有.如果希望在类中定义的成员被所有实例共享. 此时可以使用类常量或静态成员来实现,接下来将针对类常量和 ...
- Python代码审计中一些需要重点关注的项
SQL注入: 如果是常规没有进行预编译,或者直接使用原生的进行拼凑,那么在view的时候就需要多去观察了 [PythonSQL预编译]https://www.cnblogs.com/sevck/p/6 ...
- C语言学习笔记---好用的函数memcpy与memset
这个主要用于我个人的学习笔记,便于以后查询,顺便分享给大家. 想必在用C的时候难免会与数组,指针,内存这几样东西打交道,先以数组为例,例如有一个数组int a[5] = {1, 2, 3, 4, 5} ...
- pycharm git工具与coding.net结合
前提:coding.net中的项目是私密项目 问题描述:在使用pycharm自带的git工具clone(或者push)代码时出现 错误如下:Push failed: Failed with error ...
- Django的contenttypes应用、缓存相关
一.django的contenttypes contenttypes 是Django内置的一个应用 , 可以追踪项目中所有app 和 model 的对应关系, 并记录djang_content_typ ...
- log4j:WARN No appenders could be found for logger 解决办法
转自:https://blog.csdn.net/chw0629/article/details/80567936 使用log4j时不起作用,每次执行完出现以下提示: log4j:WARN No ap ...