Oracle树查询的最重要的就是select...start with... connect by ...prior 语法了。依托于该语法,我们可以将一个表形结构的中以树的顺序列出来。在下面列述了Oracle中树型查询的常用查询方式以及经常使用的与树查询相关的Oracle特性函数等,在这里只涉及到一张表中的树查询方式而不涉及多表中的关联等。
以我做过的一个项目中的表为例,表结构如下:
Sql代码
1. CREATE TABLE FLFL
2. (
3. ID NUMBER NOT NULL,
4. MC NVARCHAR2(20),
5. FLJB NUMBER,
6. SJFLID NUMBER
7. )
FLJB是作为树的级别,在很多查询中可以加快SQL的查询效率。在下面演示的功能基本上不使用这个关键字。
SJFLID存储的是上级ID,如果是顶级父节点,该SJFLID为null(得补充一句,当初的确是这样设计的,不过现在知道,表中最好别有null记录,这会引起全文扫描,建议改成0代替)。
我们从最基本的操作,逐步列出树查询中常见的操作,所以查询出来的节点以家族中的辈份作比方。
1. 查找树中的所有顶级父节点(辈份最长的人)。 假设这个树是个目录结构,那么第一个操作总是找出所有的顶级节点,再根据该节点找到其下属节点。
Sql代码
1. SELECT * FROM flfl WHERE sjflid IS NULL;
这是个引子,没用到树型查询。
2.查找一个节点的直属子节点(所有儿子)。 如果查找的是直属子类节点,也是不用用到树型查询的。
Sql代码
1. SELECT * FROM flfl WHERE sjflid = 819459;
这个可以找到ID为819459的直属子类节点。
3.查找一个节点的所有 直属子节点(所有后代)。
Sql代码
1. SELECT * FROM flfl START WITH ID = 819459 CONNECT BY sjflid = PRIOR ID;
这个查找的是ID为819459的节点下的所有直属子类节点,包括子辈的和孙子辈的所有直属节点。
4.查找一个节点的直属父节点(父亲)。 如果查找的是节点的直属父节点,也是不用用到树型查询的。
Sql代码
1. SELECT b.* FROM flfl a JOIN flfl b ON a.sjflid = b.ID WHERE a.ID = 6758;
这个找到的是ID为6758的节点的直属父节点,要用到同一张表的关联了。
5.查找一个节点的所有直属父节点(祖宗)。
Sql代码
1. SELECT * FROM flfl START WITH ID = 6758 CONNECT BY PRIOR sjflid = ID;
这里查找的就是ID为6758的所有直属父节点,打个比方就是找到一个人的父亲、祖父等。但是值得注意的是这个查询出来的结果的顺序是先列出子类节点再列出父类节点,姑且认为是个倒序吧。
上面列出两个树型查询方式,第3条语句和第5条语句,这两条语句之间的区别在于prior关键字的位置不同,所以决定了查询的方式不同。 当sjflid = PRIOR ID时,数据库会根据当前的ID迭代出sjflid与该ID相同的记录,所以查询的结果是迭代出了所有的子类记录;而PRIOR ID = sjflid时,数据库会跟据当前的sjflid来迭代出与当前的sjflid相同的id的记录,所以查询出来的结果就是所有的父类结果。
以下是一系列针对树结构的更深层次的查询,这里的查询不一定是最优的查询方式,或许只是其中的一种实现而已。
6.查询一个节点的兄弟节点(亲兄弟)。
Sql代码
1. SELECT a.*
2. FROM flfl a
3. WHERE EXISTS (SELECT *
4. FROM flfl b
5. WHERE a.sjflid = b.sjflid AND b.ID = 6757);
这里查询的就是与ID为6757的节点同属一个父节点的节点了,就好比亲兄弟了。
7.查询与一个节点同级的节点(族兄弟)。 如果在表中设置了级别的字段,上表中的FLJB,那么在做这类查询时会很轻松,同一级别的就是与那个节点同级的,在这里列出不使用该字段时的实现!
Sql代码
1. WITH tmp AS
2. (SELECT a.*, LEVEL lev
3. FROM flfl a
4. START WITH a.sjflid IS NULL
5. CONNECT BY a.sjflid = PRIOR a.ID)
6. SELECT *
7. FROM tmp
8. WHERE lev = (SELECT lev
9. FROM tmp
10. WHERE ID = 819394)
这里使用两个技巧,一个是使用了LEVEL来标识每个节点在表中的级别,还有就是使用with语法模拟出了一张带有级别的临时表。
8.查询一个节点的父节点的的兄弟节点(伯父与叔父)。
Sql代码
1. WITH tmp AS
2. (SELECT flfl.*, LEVEL lev
3. FROM flfl
4. START WITH sjflid IS var cpro_id = "u6292429";
小编还为您整理了以下内容,可能对您也有帮助:
Oracle树查询及相关函数
Oracle树查询的最重要的就是select start with connect by prior 语法了 依托于该语法 我们可以将一个表形结构的中以树的顺序列出来 在下面列述了Oracle中树型查询的常用查询方式以及经常使用的与树查询相关的Oracle特性函数等 在这里只涉及到一张表中的树查询方式而不涉及多表中的关联等
以我做过的一个项目中的表为例 表结构如下
Sql代码
CREATE TABLE FLFL
(
ID NUMBER NOT NULL
MC NVARCHAR ( )
FLJB NUMBER
SJFLID NUMBER
)
FLJB是作为树的级别 在很多查询中可以加快SQL的查询效率 在下面演示的功能基本上不使用这个关键字
SJFLID存储的是上级ID 如果是顶级父节点 该SJFLID为null(得补充一句 当初的确是这样设计的 不过现在知道 表中最好别有null记录 这会引起全文扫描 建议改成 代替)
我们从最基本的操作 逐步列出树查询中常见的操作 所以查询出来的节点以家族中的辈份作比方
查找树中的所有顶级父节点(辈份最长的人) 假设这个树是个目录结构 那么第一个操作总是找出所有的顶级节点 再根据该节点找到其下属节点
Sql代码
SELECT * FROM flfl WHERE sjflid IS NULL;
这是个引子 没用到树型查询
查找一个节点的直属子节点(所有儿子) 如果查找的是直属子类节点 也是不用用到树型查询的
Sql代码
SELECT * FROM flfl WHERE sjflid = ;
这个可以找到ID为 的直属子类节点
查找一个节点的所有 直属子节点(所有后代)
Sql代码
SELECT * FROM flfl START WITH ID = CONNECT BY sjflid = PRIOR ID;
这个查找的是ID为 的节点下的所有直属子类节点 包括子辈的和孙子辈的所有直属节点
查找一个节点的直属父节点(父亲) 如果查找的是节点的直属父节点 也是不用用到树型查询的
Sql代码
SELECT b * FROM flfl a JOIN flfl b ON a sjflid = b ID WHERE a ID = ;
这个找到的是ID为 的节点的直属父节点 要用到同一张表的关联了
查找一个节点的所有直属父节点(祖宗)
Sql代码
SELECT * FROM flfl START WITH ID = CONNECT BY PRIOR sjflid = ID;
这里查找的就是ID为 的所有直属父节点 打个比方就是找到一个人的父亲 祖父等 但是值得注意的是这个查询出来的结果的顺序是先列出子类节点再列出父类节点 姑且认为是个倒序吧
上面列出两个树型查询方式 第 条语句和第 条语句 这两条语句之间的区别在于prior关键字的位置不同 所以决定了查询的方式不同 当sjflid = PRIOR ID时 数据库会根据当前的ID迭代出sjflid与该ID相同的记录 所以查询的结果是迭代出了所有的子类记录 而PRIOR ID = sjflid时 数据库会跟据当前的sjflid来迭代出与当前的sjflid相同的id的记录 所以查询出来的结果就是所有的父类结果
以下是一系列针对树结构的更深层次的查询 这里的查询不一定是最优的查询方式 或许只是其中的一种实现而已
查询一个节点的兄弟节点(亲兄弟)
Sql代码
SELECT a *
FROM flfl a
WHERE EXISTS (SELECT *
FROM flfl b
WHERE a sjflid = b sjflid AND b ID = );
这里查询的就是与ID为 的节点同属一个父节点的节点了 就好比亲兄弟了
查询与一个节点同级的节点(族兄弟) 如果在表中设置了级别的字段 上表中的FLJB 那么在做这类查询时会很轻松 同一级别的就是与那个节点同级的 在这里列出不使用该字段时的实现!
Sql代码
WITH tmp AS
(SELECT a * LEVEL lev
FROM flfl a
START WITH a sjflid IS NULL
CONNECT BY a sjflid = PRIOR a ID)
SELECT *
FROM tmp
WHERE lev = (SELECT lev
FROM tmp
WHERE ID = )
这里使用两个技巧 一个是使用了LEVEL来标识每个节点在表中的级别 还有就是使用with语法模拟出了一张带有级别的临时表
查询一个节点的父节点的的兄弟节点(伯父与叔父)
Sql代码
WITH tmp AS
(SELECT flfl * LEVEL lev
FROM flfl
START WITH sjflid IS NULL
CONNECT BY sjflid = PRIOR ID)
SELECT b *
FROM tmp b
(SELECT *
FROM tmp
WHERE ID = AND lev = ) a
WHERE b lev =
UNION ALL
SELECT *
FROM tmp
WHERE sjflid = (SELECT DISTINCT x ID
FROM tmp x
tmp y
(SELECT *
FROM tmp
WHERE ID = AND lev > ) z
WHERE y ID = z sjflid AND x ID = y sjflid);
这里查询分成以下几步 首先 将第 个一样 将全表都使用临时表加上级别 其次 根据级别来判断有几种类型 以上文中举的例子来说 有三种情况 ( )当前节点为顶级节点 即查询出来的lev值为 那么它没有上级节点 不予考虑 ( )当前节点为 级节点 查询出来的lev值为 那么就只要保证lev级别为 的就是其上级节点的兄弟节点 ( )其它情况就是 以及以上级别 那么就要选查询出来其上级的上级节点(祖父) 再来判断祖父的下级节点都是属于该节点的上级节点的兄弟节点 最后 就是使用UNION将查询出来的结果进行结合起来 形成结果集
查询一个节点的父节点的同级节点(族叔)
这个其实跟第 种情况是相同的
Sql代码
WITH tmp AS
(SELECT a * LEVEL lev
FROM flfl a
START WITH a sjflid IS NULL
CONNECT BY a sjflid = PRIOR a ID)
SELECT *
FROM tmp
WHERE lev = (SELECT lev
FROM tmp
WHERE ID = )
只需要做个级别判断就成了
基本上 常见的查询在里面了 不常见的也有部分了 其中 查询的内容都是节点的基本信息 都是数据表中的基本字段 但是在树查询中还有些特殊需求 是对查询数据进行了处理的 常见的包括列出树路径等
补充一个概念 对于数据库来说 根节点并不一定是在数据库中设计的顶级节点 对于数据库来说 根节点就是start with开始的地方
下面列出的是一些与树相关的特殊需求
名称要列出名称全部路径
这里常见的有两种情况 一种是是从顶级列出 直到当前节点的名称(或者其它属性) 一种是从当前节点列出 直到顶级节点的名称(或其它属性) 举地址为例 国内的习惯是从省开始 到市 到县 到居委会的 而国外的习惯正好相反(老师说的 还没接过国外的邮件 谁能寄个瞅瞅 )
从顶部开始
Sql代码
SELECT SYS_CONNECT_BY_PATH (mc / )
FROM flfl
WHERE ID =
START WITH sjflid IS NULL
CONNECT BY sjflid = PRIOR ID;
从当前节点开始
Sql代码
SELECT SYS_CONNECT_BY_PATH (mc / )
FROM flfl
START WITH ID =
CONNECT BY PRIOR sjflid = ID;
在这里我又不得不放个牢了 oracle只提供了一个sys_connect_by_path函数 却忘了字符串的连接的顺序 在上面的例子中 第一个SQL是从根节点开始遍历 而第二个SQL是直接找到当前节点 从效率上来说已经是千差万别 更关键的是第一个SQL只能选择一个节点 而第二个SQL却是遍历出了一颗树来 再次PS一下
sys_connect_by_path函数就是从start with开始的地方开始遍历 并记下其遍历到的节点 start with开始的地方被视为根节点 将遍历到的路径根据函数中的分隔符 组成一个新的字符串 这个功能还是很强大的
列出当前节点的根节点
在前面说过 根节点就是start with开始的地方
Sql代码
SELECT CONNECT_BY_ROOT mc flfl *
FROM flfl
START WITH ID =
CONNECT BY PRIOR sjflid = ID;
connect_by_root函数用来列的前面 记录的是当前节点的根节点的内容
列出当前节点是否为叶子
这个比较常见 尤其在动态目录中 在查出的内容是否还有下级节点时 这个函数是很适用的
Sql代码
SELECT CONNECT_BY_ISLEAF flfl *
FROM flfl
START WITH sjflid IS NULL
CONNECT BY sjflid = PRIOR ID;
connect_by_isleaf函数用来判断当前节点是否包含下级节点 如果包含的话 说明不是叶子节点 这里返回 反之 如果不包含下级节点 这里返回
lishixin/Article/program/Oracle/201311/11193如何实现Oracle子父节点查询
一般来说这种递归查询应该用start with connect by,不过你的表中少了一列,就是当前节点的父节点列,所以这个应该不能用。
比如元数据为4列 其中两列类似为
父节点编码 当前节点编码
010001000000 010001010000
010001010000 010001010200
那么start with connect by就可以用了,这里因为没有这个父节点编码的字段,所以不能用。
那么查询就麻烦一些,我想到了一个办法,不过是这个表结构的特例,希望能帮到你
第一步是截取输入的diccode的非零长度,我想到的办法是length(trim(tailing 0 from '输入或计算得到的diccode值'))--假设得到的是8位,假设为01000101 8位
那么所有的子节点就是 diccode like substr(diccode,1,length(trim(tailing 0 from '输入或计算得到的diccode值')))%
意思就是 diccode like '01000101%'(这不就是所有该节点的子节点了么,包括自身)
(以上部分的写法要斟酌一下,%是通配符,一般来说我们的写法是like ‘a%’,但是单引号部分怎么写,需不需要转译,反引号行不行,与%怎么连接,我没有环境只能写个大概意思,具体的要试验才行。)
然后求父节点,先求上一级,diccode=(case when length(trim(tailing 0 from '输入或计算得到的diccode值'))-2>0 then rpad(substr('输入或计算得到的diccode值',1, length(trim(tailing 0 from '输入或计算得到的diccode值'))-2),12,0) else 0 end)
意思就是:截取到01000101后,长度为8位,长度-2为6位那么就是010001,然后补足12位的0,为010001000000,也就是上一级父节点。如果输入为010000000000,那么第一步就直接查出所有内容了,后面这个条件用or连接,查出来的都是0,也就是diccode=0,不会干扰正常内容的显示。
然后继续-2变成-4(这样举例就变成为010000000000),再变成-6(例子中虽然也能查出来010000000000,但是前面已经查出,不会重复显示的),-8(例子中等于0,那么显示diccode=0,因为or连接所以不耽误显示),-10,我看了你的编码是12位,-10应该够了,写法同上,然后所有的条件用or连接,这样不用写过程去计算,虽然麻烦,而且速度不会太快,但是思路应该没错。
其实我一直在琢磨应该可以用start with connect by写后面的-2到-10部分,但是如果写成start那么这部分需要测试,我这里没有相关的环境,所以只能是这么写,麻烦一些。而且starwith好像没办法就相关子节点,所以我也不知道到底能不能用。
如何实现Oracle子父节点查询
一般来说这种递归查询应该用start with connect by,不过你的表中少了一列,就是当前节点的父节点列,所以这个应该不能用。
比如元数据为4列 其中两列类似为
父节点编码 当前节点编码
010001000000 010001010000
010001010000 010001010200
那么start with connect by就可以用了,这里因为没有这个父节点编码的字段,所以不能用。
那么查询就麻烦一些,我想到了一个办法,不过是这个表结构的特例,希望能帮到你
第一步是截取输入的diccode的非零长度,我想到的办法是length(trim(tailing 0 from '输入或计算得到的diccode值'))--假设得到的是8位,假设为01000101 8位
那么所有的子节点就是 diccode like substr(diccode,1,length(trim(tailing 0 from '输入或计算得到的diccode值')))%
意思就是 diccode like '01000101%'(这不就是所有该节点的子节点了么,包括自身)
(以上部分的写法要斟酌一下,%是通配符,一般来说我们的写法是like ‘a%’,但是单引号部分怎么写,需不需要转译,反引号行不行,与%怎么连接,我没有环境只能写个大概意思,具体的要试验才行。)
然后求父节点,先求上一级,diccode=(case when length(trim(tailing 0 from '输入或计算得到的diccode值'))-2>0 then rpad(substr('输入或计算得到的diccode值',1, length(trim(tailing 0 from '输入或计算得到的diccode值'))-2),12,0) else 0 end)
意思就是:截取到01000101后,长度为8位,长度-2为6位那么就是010001,然后补足12位的0,为010001000000,也就是上一级父节点。如果输入为010000000000,那么第一步就直接查出所有内容了,后面这个条件用or连接,查出来的都是0,也就是diccode=0,不会干扰正常内容的显示。
然后继续-2变成-4(这样举例就变成为010000000000),再变成-6(例子中虽然也能查出来010000000000,但是前面已经查出,不会重复显示的),-8(例子中等于0,那么显示diccode=0,因为or连接所以不耽误显示),-10,我看了你的编码是12位,-10应该够了,写法同上,然后所有的条件用or连接,这样不用写过程去计算,虽然麻烦,而且速度不会太快,但是思路应该没错。
其实我一直在琢磨应该可以用start with connect by写后面的-2到-10部分,但是如果写成start那么这部分需要测试,我这里没有相关的环境,所以只能是这么写,麻烦一些。而且starwith好像没办法就相关子节点,所以我也不知道到底能不能用。
ORACLE树查询,startwithconnectbyprior
oracle中的select语句可以用START WITH CONNECT BY PRIOR子句实现递归查询 connect by 是结构化查询中用到的 其基本语法是
select * from tablename start with cond
connect by cond
where cond ;
简单说来是将一个树状结构存储在一张表里 比如一个表中存在两个字段:
id parentid那么通过表示每一条记录的parent是谁 就可以形成一个树状结构
用上述语法的查询可以取得这棵树的所有记录
其中COND 是根结点的限定语句 当然可以放宽限定条件 以取得多个根结点 实际就是多棵树
COND 是连接条件 其中用PRIOR表示上一条记录 比如 CONNECT BY PRIOR ID=PRAENTID就是说上一条记录的ID是本条记录的PRAENTID 即本记录的父亲是上一条记录
COND 是过滤条件 用于对返回的所有记录进行过滤
对于oracle进行简单树查询(递归查询)
DEPTID NUMBER 部门id
PAREDEPTID NUMBER 父部门id(所属部门id)
NAME CHAR ( Byte) 部门名称
通过子节点向根节点追朔
Ql代码 select * from persons dept start with deptid= connect by prior paredeptid=deptid<SPAN >select * from persons dept start with deptid= connect by prior paredeptid=deptid</SPAN>
select * from persons dept start with deptid= connect by prior paredeptid=deptid
通过根节点遍历子节点
Ql代码 select * from persons dept start with paredeptid= connect by prior deptid=paredeptid
<SPAN >select * from persons dept start with paredeptid= connect by prior deptid=paredeptid</SPAN>
select * from persons dept start with paredeptid= connect by prior deptid=paredeptid
可通过level 关键字查询所在层次
Ql代码 select a * level from persons dept a start with paredeptid= connect by prior deptid=paredeptid
<SPAN >select a * level from persons dept a start with paredeptid= connect by prior deptid=paredeptid</SPAN>
select a * level from persons dept a start with paredeptid= connect by prior deptid=paredeptid
PS start with 后面所跟的就是就是递归的种子 也就是递归开始的地方
connect by prior后面的字段顺序是有讲究的
若prior缺省 则只能查询到符合条件的起始行 并不进行递归查询
例
select * from table
start with _id = HBHqfWGWPy
connect by prior _id = parent_id;
简单说来是将一个树状结构存储在一张表里 比如一个表中存在两个字段:
_id parent_id那么通过表示每一条记录的parent是谁 就可以形成一个树状结构
用上述语法的查询可以取得这棵树的所有记录
其中
条件 是根结点的限定语句 当然可以放宽限定条件 以取得多个根结点 实际就是多棵树
条件 是连接条件 其中用PRIOR表示上一条记录
比如 CONNECT BY PRIOR _id = parent_id就是说上一条记录的_id 是本条记录的parent_id 即本记录的父亲是上一条记录
条件 是过滤条件 用于对返回的所有记录进行过滤
简单介绍如下
在扫描树结构表时 需要依此访问树结构的每个节点 一个节点只能访问一次 其访问的步骤如下
第一步 从根节点开始
第二步 访问该节点
第三步 判断该节点有无未被访问的子节点 若有 则转向它最左侧的未被访问的子节点 并执行第二步 否则执行第四步
第四步 若该节点为根节点 则访问完毕 否则执行第五步
第五步 返回到该节点的父节点 并执行第三步骤
总之 扫描整个树结构的过程也即是中序遍历树的过程
. 树结构的描述
树结构的数据存放在表中 数据之间的层次关系即父子关系 通过表中的列与列间的关系来描述 如 EMP 表中的 EMPNO 和 MGR EMPNO 表示该雇员的编号 MGR 表示领导该雇员的人的编号 即子节点的 MGR 值等于父节点的 EMPNO 值 在表的每一行中都有一个表示父节点的 MGR (除根节点外) 通过每个节点的父节点 就可以确定整个树结构
在 SELECT 命令中使用 CONNECT BY 和 START WITH 子句可以查询表中的树型结构关系 其命令格式如下
SELECT
CONNECT BY {PRIOR 列名 = 列名 | 列名 =PRIOR 裂名 }
[START WITH]
其中 CONNECT BY 子句说明每行数据将是按层次顺序检索 并规定将表中的数据连入树型结构的关系中 PRIORY 运算符必须放置在连接关系的两列中某一个的前面 对于节点间的父子关系 PRIOR 运算符在一侧表示父节点 在另一侧表示子节点 从而确定查找树结构是的顺序是自顶向下还是自底向上 在连接关系中 除了可以使用列名外 还允许使用列表达式 START WITH 子句为可选项 用来标识哪个节点作为查找树型结构的根节点 若该子句被省略 则表示所有满足查询条件的行作为根节点
START WITH 不但可以指定一个根节点 还可以指定多个根节点
. 关于 PRIOR
运算符 PRIOR 被放置于等号前后的位置 决定着查询时的检索顺序
PRIOR 被置于 CONNECT BY 子句中等号的前面时 则强制从根节点到叶节点的顺序检索 即由父节点向子节点方向通过树结构 我们称之为自顶向下 的方式 如
CONNECT BY PRIOR EMPNO=MGR
PIROR 运算符被置于 CONNECT BY 子句中等号的后面时 则强制从叶节点到根节点的顺序检索 即由子节点向父节点方向通过树结构 我们称之为自底向上 的方式 例如
CONNECT BY EMPNO=PRIOR MGR
在这种方式中也应指定一个开始的节点
. 定义查找起始节点
在自顶向下查询树结构时 不但可以从根节点开始 还可以定义任何节点为起始节点 以此开始向下查找 这样查找的结果就是以该节点为开始的结构树的一枝
.使用 LEVEL
在具有树结构的表中 每一行数据都是树结构中的一个节点 由于节点所处的层次位置不同 所以每行记录都可以有一个层号 层号根据节点与根节点的距离确定 不论从哪个节点开始 该起始根节点的层号始终为 根节点的子节点为 依此类推
.节点和分支的裁剪
在对树结构进行查询时 可以去掉表中的某些行 也可以剪掉树中的一个分支 使用 WHERE 子句来限定树型结构中的单个节点 以去掉树中的单个节点 但它却不影响其后代节点(自顶向下检索时)或前辈节点(自底向顶检索时)
.排序显示
lishixin/Article/program/Oracle/201311/17814ORACLE树查询,startwithconnectbyprior
oracle中的select语句可以用START WITH CONNECT BY PRIOR子句实现递归查询 connect by 是结构化查询中用到的 其基本语法是
select * from tablename start with cond
connect by cond
where cond ;
简单说来是将一个树状结构存储在一张表里 比如一个表中存在两个字段:
id parentid那么通过表示每一条记录的parent是谁 就可以形成一个树状结构
用上述语法的查询可以取得这棵树的所有记录
其中COND 是根结点的限定语句 当然可以放宽限定条件 以取得多个根结点 实际就是多棵树
COND 是连接条件 其中用PRIOR表示上一条记录 比如 CONNECT BY PRIOR ID=PRAENTID就是说上一条记录的ID是本条记录的PRAENTID 即本记录的父亲是上一条记录
COND 是过滤条件 用于对返回的所有记录进行过滤
对于oracle进行简单树查询(递归查询)
DEPTID NUMBER 部门id
PAREDEPTID NUMBER 父部门id(所属部门id)
NAME CHAR ( Byte) 部门名称
通过子节点向根节点追朔
Ql代码 select * from persons dept start with deptid= connect by prior paredeptid=deptid<SPAN >select * from persons dept start with deptid= connect by prior paredeptid=deptid</SPAN>
select * from persons dept start with deptid= connect by prior paredeptid=deptid
通过根节点遍历子节点
Ql代码 select * from persons dept start with paredeptid= connect by prior deptid=paredeptid
<SPAN >select * from persons dept start with paredeptid= connect by prior deptid=paredeptid</SPAN>
select * from persons dept start with paredeptid= connect by prior deptid=paredeptid
可通过level 关键字查询所在层次
Ql代码 select a * level from persons dept a start with paredeptid= connect by prior deptid=paredeptid
<SPAN >select a * level from persons dept a start with paredeptid= connect by prior deptid=paredeptid</SPAN>
select a * level from persons dept a start with paredeptid= connect by prior deptid=paredeptid
PS start with 后面所跟的就是就是递归的种子 也就是递归开始的地方
connect by prior后面的字段顺序是有讲究的
若prior缺省 则只能查询到符合条件的起始行 并不进行递归查询
例
select * from table
start with _id = HBHqfWGWPy
connect by prior _id = parent_id;
简单说来是将一个树状结构存储在一张表里 比如一个表中存在两个字段:
_id parent_id那么通过表示每一条记录的parent是谁 就可以形成一个树状结构
用上述语法的查询可以取得这棵树的所有记录
其中
条件 是根结点的限定语句 当然可以放宽限定条件 以取得多个根结点 实际就是多棵树
条件 是连接条件 其中用PRIOR表示上一条记录
比如 CONNECT BY PRIOR _id = parent_id就是说上一条记录的_id 是本条记录的parent_id 即本记录的父亲是上一条记录
条件 是过滤条件 用于对返回的所有记录进行过滤
简单介绍如下
在扫描树结构表时 需要依此访问树结构的每个节点 一个节点只能访问一次 其访问的步骤如下
第一步 从根节点开始
第二步 访问该节点
第三步 判断该节点有无未被访问的子节点 若有 则转向它最左侧的未被访问的子节点 并执行第二步 否则执行第四步
第四步 若该节点为根节点 则访问完毕 否则执行第五步
第五步 返回到该节点的父节点 并执行第三步骤
总之 扫描整个树结构的过程也即是中序遍历树的过程
. 树结构的描述
树结构的数据存放在表中 数据之间的层次关系即父子关系 通过表中的列与列间的关系来描述 如 EMP 表中的 EMPNO 和 MGR EMPNO 表示该雇员的编号 MGR 表示领导该雇员的人的编号 即子节点的 MGR 值等于父节点的 EMPNO 值 在表的每一行中都有一个表示父节点的 MGR (除根节点外) 通过每个节点的父节点 就可以确定整个树结构
在 SELECT 命令中使用 CONNECT BY 和 START WITH 子句可以查询表中的树型结构关系 其命令格式如下
SELECT
CONNECT BY {PRIOR 列名 = 列名 | 列名 =PRIOR 裂名 }
[START WITH]
其中 CONNECT BY 子句说明每行数据将是按层次顺序检索 并规定将表中的数据连入树型结构的关系中 PRIORY 运算符必须放置在连接关系的两列中某一个的前面 对于节点间的父子关系 PRIOR 运算符在一侧表示父节点 在另一侧表示子节点 从而确定查找树结构是的顺序是自顶向下还是自底向上 在连接关系中 除了可以使用列名外 还允许使用列表达式 START WITH 子句为可选项 用来标识哪个节点作为查找树型结构的根节点 若该子句被省略 则表示所有满足查询条件的行作为根节点
START WITH 不但可以指定一个根节点 还可以指定多个根节点
. 关于 PRIOR
运算符 PRIOR 被放置于等号前后的位置 决定着查询时的检索顺序
PRIOR 被置于 CONNECT BY 子句中等号的前面时 则强制从根节点到叶节点的顺序检索 即由父节点向子节点方向通过树结构 我们称之为自顶向下 的方式 如
CONNECT BY PRIOR EMPNO=MGR
PIROR 运算符被置于 CONNECT BY 子句中等号的后面时 则强制从叶节点到根节点的顺序检索 即由子节点向父节点方向通过树结构 我们称之为自底向上 的方式 例如
CONNECT BY EMPNO=PRIOR MGR
在这种方式中也应指定一个开始的节点
. 定义查找起始节点
在自顶向下查询树结构时 不但可以从根节点开始 还可以定义任何节点为起始节点 以此开始向下查找 这样查找的结果就是以该节点为开始的结构树的一枝
.使用 LEVEL
在具有树结构的表中 每一行数据都是树结构中的一个节点 由于节点所处的层次位置不同 所以每行记录都可以有一个层号 层号根据节点与根节点的距离确定 不论从哪个节点开始 该起始根节点的层号始终为 根节点的子节点为 依此类推
.节点和分支的裁剪
在对树结构进行查询时 可以去掉表中的某些行 也可以剪掉树中的一个分支 使用 WHERE 子句来限定树型结构中的单个节点 以去掉树中的单个节点 但它却不影响其后代节点(自顶向下检索时)或前辈节点(自底向顶检索时)
.排序显示
lishixin/Article/program/Oracle/201311/17814oracle如何查询任意节点下的所有子节点
向下递归+叶子节点过滤就行了,例子:
--模拟数据with tmp(id,pid) as
(SELECT 'A','' FROM DUAL UNION ALL
SELECT 'B','A' FROM DUAL UNION ALL
SELECT 'C','A' FROM DUAL UNION ALL
SELECT 'D','B' FROM DUAL UNION ALL
SELECT 'E','B' FROM DUAL UNION ALL
SELECT 'F','C' FROM DUAL UNION ALL
SELECT 'G','F' FROM DUAL )
SELECT ID FROM TMP T
WHERE CONNECT_BY_ISLEAF=1 --只显示叶子节点
START WITH T.ID='A' --递归起点,即查询条件
CONNECT BY PRIOR ID=PID --递归条件,向下递归
oracle 中怎样递归查询出子节点的最上层父节点,并且其父节点是自身
1、创建测试表,create table test_connect(id number, p_id number);
2、插入测试数据,
insert into test_connect values(1,1);
insert into test_connect values(2,1);
insert into test_connect values(3,2);
insert into test_connect values(4,3);
commit;
3、查询数据表内容,select * from test_connect ,
4、执行递归查询语句,加入nocycle要素,不会出现【ORA-01436: 用户数据中的 CONNECT BY 循环的错误】,执行结果如下,
select *
from test_connect t
start with id = 4
connect by nocycle prior t.p_id = t.id