sql
树形递归查询是数据库查询的一种特殊情形,也是组织结构、行政区划查询的一种最常用的的情形之一。下面对该种查询进行一些总结:
1、查找某个节点下面子孙节点
select * from table start with id=1 connect by prior id=pid
2、查找节点的祖先节点
select * from table start with id=5 connect by prior pid=id
在树形结构节点很多的情况一下,一般会采用异步刷新的方式进行,在默认加载的情况下,会展开到某个层级。这种情况下,不但要获取某个节点的祖先节点,还需要获取祖先节点的兄弟节点,在这种情况下可以通过level
进行
select id,pid,level from tb where level>1
connect by prior id=pid
start with id=1
order by level
显示出树的级别查询
select menu_id,rpad(' ',(level-1)*4)||menu_name,level from menu
connect by parent_id = prior menu_id
start with parent_id is null;
浅谈oracle
树状结构层级查询
oracle
树状结构查询即层次递归查询,是sql
语句经常用到的,在实际开发中组织结构实现及其层次化实现功能也是经常遇到的,虽然我是一个java程序开发者,我一直觉得只要精通数据库那么对于java开发你就成功了三分之一,本篇中主要介绍start with...connect by prior 、order by 、sys_connect_by_path
。
概要:树状结构通常由根节点、父节点、子节点和叶节点组成,简单来说,一张表中存在两个字段,dept_id
,par_dept_id
,那么通过找到每一条记录的父级id
即可形成一个树状结构,也就是par_dept_id(子)=dept_id(父)
,通俗的说就是这条记录的par_dept_id
是另外一条记录也就是父级的dept_id
,其树状结构层级查询的基本语法是:
SELECT [LEVEL],*
FEOM table_name
START WITH 条件1
CONNECT BY PRIOR 条件2
ORDER BY 排序字段
说明:
LEVEL
—伪列,用于表示树的层次
条件1—根节点的限定条件,当然也可以放宽权限,以获得多个根节点,也就是获取多个树
条件2—连接条件,目的就是给出父子之间的关系是什么,根据这个关系进行递归查询
排序字段—对所有返回记录进行排序
对prior
说明:要的时候有两种写法:connect by prior dept_id=par_dept_id
或 connect by dept_id=prior par_dept_id
,前一种写法表示采用自上而下的搜索方式(先找父节点然后找子节点),后一种写法表示采用自下而上的搜索方式(先找叶子节点然后找父节点)。
树状结构层次化查询需要对树结构的每一个节点进行访问并且不能重复,其访问步骤为:
大致意思就是扫描整个树结构的过程即遍历树的过程,其用语言描述就是:
步骤一:从根节点开始;
步骤二:访问该节点;
步骤三:判断该节点有无未被访问的子节点,若有,则转向它最左侧的未被访问的子节,并执行第二步,否则执行第四步;
步骤四:若该节点为根节点,则访问完毕,否则执行第五步;
步骤五:返回到该节点的父节点,并执行第三步骤。
除此之外,sys_connect_by_path
函数是和connect by
一起使用的,在实战中具体带目的具体介绍!
实战:最近做项目的组织结构,对于部门的各级层次显示,由于这部分掌握不牢固,用最笨的like
模糊查询解决了,虽然功能实现了,但是问题很多,如扩展性不好,稍微改下需求就要进行大改,不满意最后对其进行了优化。在开发中能用数据库解决的就不要用java去解决,这也是我一直保持的想法并坚持着。
对于建表语句及其测试数据我放在另外一篇博客中,需要进行测试的可以过去拷贝运行测试验证下!
在这张表中有三个字段:
dept_id
部门主键id
;
dept_name
部门名称;
dept_code
部门编码;
par_dept_id
父级部门id(首级部门为 -1);
1.当前节点遍历子节点(遍历当前部门下所有子部门包括本身)
select t.dept_id, t.dept_name, t.dept_code, t.par_dept_id, level
from SYS_DEPT t
start with t.dept_id = '40288ac45a3c1e8b015a3c28b4ae01d6'
connect by prior t.dept_id = t.par_dept_id
order by level, t.dept_code
结果:
dept_id=40288ac45a3c1e8b015a3c28b4ae01d6
是客运部主键,对其下的所有子部门进行遍历,同时用 order by level,dept_code
进行排序 以便达到实际生活中想要的数据;共31条数据,部分数据如图所示:
但是:
有问题啊,如果你想在上面的数据中获取层级在2也就是level=2
的所有部门,发现刚开始的时候介绍的语言不起作用?并且会报ORA-00933:sql命令未正确结束
,why?
这个我暂时也没有得到研究出理论知识,但是改变下where level='2'
的位置发现才会可以的。错误的和正确的sql我们对比一下,以后会用就行,要是路过的大神知道为什么,还请告知下,万分感谢!
错误sql:
select t.dept_id, t.dept_name, t.dept_code, t.par_dept_id, level
from SYS_DEPT t
start with t.dept_id = '40288ac45a3c1e8b015a3c28b4ae01d6'
connect by prior t.dept_id = t.par_dept_id
where level = '2'
order by level, t.dept_code
正确sql:
select t.dept_id, t.dept_name, t.dept_code, t.par_dept_id, level
from SYS_DEPT t
where level = '2'
start with t.dept_id = '40288ac45a3c1e8b015a3c28b4ae01d6'
connect by prior t.dept_id = t.par_dept_id
order by level, t.dept_code
当然了,这个对其他形式的where
过滤所有返回记录没有影响的,这个只是一个例外!
2.sys_connect_by_path
函数求父节点到子节点路径
简单介绍下,在oracle中sys_connect_by_path
与connect by
一起使用,也就是先要有或建立一棵树,否则无用还会报错。它的主要作用体现在path
上即路径,是可以吧一个父节点下的所有节点通过某个字符区分,然后链接在一个列中显示。
sys_connect_by_path(column,clear)
,其中column
是字符型或能自动转换成字符型的列名,它的主要目的就是将父节点到当前节点的“path
”按照指定的模式出现,char
可以是单字符也可以是多字符,但不能使用列值中包含的字符,而且这个参数必须是常量,且不允许使用绑定变量,clear
不要用逗号。
文字容易让人疲劳,放图和代码吧!
select sys_connect_by_path(t.dept_name,'-->'),t.dept_id, t.dept_name, t.dept_code, t.par_dept_id, level
from SYS_DEPT t
start with t.dept_id = '40288ac45a3c1e8b015a3c28b4ae01d6'
connect by prior t.dept_id = t.par_dept_id
order by level, t.dept_code
结果: