设为首页 收藏本站
查看: 1050|回复: 0

[经验分享] 令人迷糊的Oracle递归查询(start with)

[复制链接]
YunVN网友  发表于 2016-8-15 06:24:31 |阅读模式
  写代码时碰到要弄清楚Oracle的role之间的传递关系,就是有role A的话,可以通过grant A to B,把A赋予给B,又通过grant B to C .那我想知道所有role中,有哪些role具有A的权限.
  上网一查发现有个递归查询,不过都讲的不是太详细,而那Oracle整的那用法实在太怪异了,跟我们平时用的SQL差的太远,所以琢磨了好一阵子脑子才转过弯呢.
树形结构
  可能一看到递归查询这样太专业的名词大家就迷糊了.实际上可以看成有一个树形结构,然后我们要怎么把所有树的所有结点查找出来.学数据结构的时候我们知道要遍历一个树结构有啥前序遍历,中序遍历,后序遍历.反正挺麻烦的.不像遍历个数组那么容易的.那实际上在Oracle的一个表中也可以保存树形结构信息.你要查询所有的树节点,自己整个函数或存储过程去整肯定是超级麻烦的.Oracle提供了一个简单的机制帮助你.要用到start with ...connectby等关键字.先来假定有下面这样一个简单的树形结构存储在表中.
  create table Tree(son char(10), father char(10)); 然后插入些信息变成这样的表
  
  SON FATHTER
  孙子SB儿子
  孙子NB儿子
  儿子 爸爸
  爸爸 爷爷
  
  很显然这是一个简单的树形结构
  孙子SB
  ^
  |
  爷爷 --> 爸爸 --> 儿子 -->孙子NB
  
  
递归查询
  假如要查询出以爷爷为根的树的所有节点值咋整呢 ?如果数据少多来几个where嵌套就行.但要是树层次有几百那会搞死人了啊.于是我们就用Oracle提供的递归查询.先看下SQL的写法然后再讲解
  SELECT son FROM tree
  START WITH father = '爷爷'
  CONNECT BY PRIOR son = father;
  返回的结果为 爸爸 儿子 孙子NB 孙子SB
  代码看起来很短,但是极为怪异,脑子半天都不容易转过弯呢.实际上我们不把这个SQL语句跟一般的SQL类比,而把它当作给一些函数指定一些参数的赋值语句才更容易理解.
  那怎么来理解上面的SQL呢?
  首先把SELECT son FROM tree还是看成一般sql一样,就是要查找son这一列的信息.而把以START WITH开头的后面所有东东看成一个where限制条件.其中START WITH 是指定
  树的根,这里指定的根是 '爷爷',实际上你还可以指定多个根的,比如 father in ('爷爷', '爸爸') .
  而CONNECT BY PRIOR son = father相当于表明在递归的过程中,查找到的树中其它节点接着又作为根结点.然后继续递归. 反正看这sql语句前先想下树形结构,然后想下一般编程语言中的递归函数.再来看时就容易理解点.实际上我觉得Oracle这样设计不太好.如果用户只是简单的指定的一个根节点然后知道树中其他节点信息.那么就直接用START WITH指定根就行了.CONNECT BY PRIOR显得有点多余,可以不用用户去指定.当作一个默认值,只有需要其他一些更复杂的操作时才让用户明确指定.这样就不容易误导人了.
  为了便于理解可以可以CONNECT BY那一行当作多余的,只记住要查询的列名放前面,根列名放等号后面就行.这样只要指定树的根结点就比较好理解了.
  
start with ,connect by prior其他变形
  上面讲的用START WITH 指定树的根,然后用CONNECT BY指定递归条件.是最简单的也是最常用的形式.但实际上还有些变形.
1.START WITH 可以省略
  比如
  SELECT son FROM tree
  CONNECT BY PRIOR son = father;
  此时不指定树的根的话,就默认把Tree整个表中的数据从头到尾遍历一次,每一个数据做一次根,然后遍历树中其他节点信息.
  在这个例子中,上面的SQL等价于
  SELECT son FROM tree
  START WITH father IN (爷爷,爸爸,儿子,孙子NB,孙子SB)
  CONNECT BY PRIOR son = father;
  那查询到的结果如下,有很多重复信息的
  爸爸,儿子,孙子NB,孙子SB 儿子,孙子NB,孙子SB 孙子NB,孙子SB
  
2.START WITH 与CONNECT BY PRIOR位置可互换
  
  SELECT son FROM tree
  CONNECT BY PRIOR son = father
  START WITH father = '爷爷';
  这语句与最开头那个是等价的
  
3.nocycle关键字
  我们知道标准的树结构中是不会有环的,但表中的树形结构不是标准的,有可能导致环的出现
  比如
  ---------孙子SB
  | ^
  | |
  爷爷 --> 爸爸 --> 儿子 -->孙子NB
  哎在这里想用线条整个箭头出来真他妈麻烦啊.我又有点懒不想用其他画图工具啥的啊.反正假设儿子的儿子是孙子SB ,而孙子SB的儿子是爸爸.这样就形成一个环了.
  当然在Oracle中的role是禁止出现循环的.比如你grant A to B ,grant B to C .再来个grant C to A会出错的.
  假如有个上面的环,在再使用开始的递归查询语言会出错.得用nocycle关键字指定忽略环.
  SELECT son FROM tree
  START WITH father = '爷爷'
  CONNECT BY NOCYCLEPRIOR son = father;
  此时结果是
  爸爸 儿子 孙子NB
  你会注意到由于忽略了环,所以孙子SB的信息也被忽略掉了.
  
4. connect by prior 后面条件顺序的改变 (???)
  SELECT son FROM tree
  START WITH father = '爷爷'
  CONNECT BY PRIOR son = father;
  这是开头的写法,但实际上也可以写成father = son倒过来写.有人说没倒过来是从上到下,从根往下.如果倒过来则是从下到上.哎不过我测试了下发现不是那么回事.结果也有点乱七八糟的.没想明白是啥规律.反正还有待研究啊
  
5.还可以加where条件
  我上面说了可以把start with ,connect 假装看成where 条件一样.所以在这个sql语句其他地方还可以加其他where 语句,可以看成与递归查询无关.只是对整个结果起过滤作用
  比如
  SELECT son FROM tree WHERE son = '孙子SB'
  START WITH father = '爷爷'
  CONNECT BY PRIOR son = father;
  
  当然你不能在最后部分加where,不能在connect by最后面再加.

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-257709-1-1.html 上篇帖子: ★ oracle子查询分解(分而治之) 下篇帖子: Oracle优化经典文章------索引原理篇·转
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表