Oracle中with as、START with ... CONNECT by PRIOR (CONNECT_BY_ROOT)的用法

Oracle中with as、START with ... CONNECT by PRIOR (CONNECT_BY_ROOT)的用法

一 、with as 

(一)含义

WITH AS查询语句,也叫子查询部分(subquery factoring),定义一个SQL共用片断,该SQL片断会被整个SQL语句所用到。 它不是以select开始,而是以“WITH”关键字开头。在真正进行查询之前预先构造了一个临时表,之后便可多次使用它做进一步的分析和处理。

(二)语法:每个子查询以逗号分隔,要注意:最后一个没有任何符号。

with query1 AS

(select ...from ....where ..),

query2  AS

(select...from ...where..),

query3 AS

(select...from ...where..)

SELECT ...FROM query1,quer2,query3 

where ....;

(三)用途

1、提高SQL语句可读性。

  增加了SQL的易读性,如果构造了多个子查询,结构会更清晰。

2、提高执行效率。

with as在查询的时候建立临时表,数据是写入了内存中。“一次分析,多次使用”,达到提高sql执行性能的地方,达到了“少读”的目标。

如果WITH AS短语所定义的表名被调用两次以上,则优化器会自动将WITH AS短语所获取的数据放入一个TEMP表里,如果只是被调用一次,则不会。而提示materialize则是强制将WITH AS短语里的数据放入一个全局临时表里。很多查询通过这种方法都可以提高速度。

二、 递归查询 start with ... CONNECT by PRIOR

(一)含义

一般用来查找存在父子关系的数据,也就是树形结构的数据;其返还的数据也能够明确的区分出每一层的数据。

(二)语法

SELECT ... FROM    + 表名

WHERE              + 条件3

START WITH         + 条件1

CONNECT BY PRIOR   + 条件2

--示例

Select * From DEMO

Start With ID = '00001'

Connect By Prior ID = PID

start with condition1 是用来限制第一层的数据,或者叫根节点数据;以这部分数据为基础来查找第二层数据,然后以第二层数据查找第三层数据以此类推。

connect by [prior] id=parentid 这部分是用来指明oracle在查找数据时以怎样的一种关系去查找;比如说查找第二层的数据时用第一层数据的id去跟表里面记录的parentid字段进行匹配,如果这个条件成立那么查找出来的数据就是第二层数据,同理查找第三层第四层…等等都是按这样去匹配。

条件1: 表示从哪个节点开始查找, 也就是通过条件1 查询到的数据, 作为后续查询的起始节点(参数)。

当然可以放宽限定条件,如 ID in ('00001', '00011')以取得多个根节点,也就是多棵树;在连接关系中,除了可以使用列明外,还允许使用列表达式。

如果省略Start With

就默认把所有满足查询条件的Tree整个表中的数据从头到尾遍历一次,每一个数据做一次根,然后遍历树中其他节点信息。

条件2: 是连接条件,其中用PRIOR表示上一条记录,例如CONNECT BY PRIOR ID = PID,意思就是上一条记录的ID是本条记录的PID,即本记录的父亲是上一条记录。CONNECT BY子句说明每行数据将是按照层次顺序检索,并规定将表中的数据连入树形结构的关系中。

Prior 在父节点的一侧表示, 自底向上查, 在 子节点的一侧表示 自上向下查询;

条件3: 不能用在 Connect By 后, 这里的条件判断, 等价于 在最后查询出结果列表之后, 再进行条件筛选; 并非 删除掉 节点及子节点;

(三)语法变种

select * from table [start with condition1]

    connect by [prior] id=parentid

select * from table [start with condition1]

    connect by id= [prior] parentid

这种用法就表示从下往上查找数据,可以理解为从叶子节点往上查找父级几点,用第一层数据的parentid去跟表记录里面的id进行匹配,匹配成功那么查找出来的就是第二层数据;上面的那种就是从父级节点往下查找叶子节点。

(四)其他特性

1、level关键字,表示当前节点所处层级, 这里的层级指的是 从 start with 查询到的节点开始往下算起, 当前属于第几层级。第一层是数字1,第二层数字2,依次递增。

2、CONNECT_BY_ROOT方法,能够获取第一层集结点结果集中的任意字段的值;例CONNECT_BY_ROOT(字段名)。

3、nocycle关键字, 有时候数据本身 不合理会导致出现循环的问题, 如 将上述的 ID '00001' 记录的 'PID' 也改为 '00001', 会出现循环的问题, 这是, 需要用到 nocycle 即可消除循环;

Connect By nocycle Prior ID = PID 即可。

4、connect_by_isleaf 表示当前节点是否是叶子节点

Select ID, PID, DSC,

connect_by_isleaf isLeaf,

LEVEL

From DEMO

Connect By nocycle Prior ID = PID

Start With ID = '00001';

--结果

ID      PID     DSC  isLeaf     LEVEL

00001   00001   中国  0           0

00011   00001   陕西  0           1

00111   00011   西安  1           2

00112   00011   咸阳  1           2

00113   00011   延安  1           2

00012   00001   贵州  1           1

00013   00001   河南  1           1

另外一点: 如果在查询语句中 Select ID, PID, DSC, connect_by_isleaf isLeaf, LEVEL - 1 LEVEL 这种查询方式的话, 在 WHERE 判断条件中, 只需要判断 LEVEL = 1, 就可以取出 当前查询节点的 子节点(由于LEVEL 也是 伪列, 需要用子查询的方式);

(五)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 NOCYCLE PRIOR 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;

--代码演示

--获取首条评论

with fatherComment as

 (select t.add_time,

         t.comm_content,

         decode(t.top_target_type,

                'image',

                '单图',

                'post',

                '帖子',

                'article',

                '文章',

                '其它') productType,

         t.target_type,

         t.target_id,

         t.comment_id,

         t.device_id

    from dbread.t_usercomment t

   where t.top_target_type not in

         ('comic', 'comic_part', 'cartoon', 'cartoon_part')

     and t.target_type != 'comment'

     and t.add_time >= date '2021-6-1'

     and t.add_time < date '2021-6-10'

   order by t.add_time desc ),

--获取评论的评论:使用start with... connect by prior获取父子层级树状数据

childComment as

 (select *

    from (select t.add_time,

                 t.comm_content,

                 t.target_id,

                 t.comment_id,

                 t.device_id,

                 LEVEL lev, --评论在结构树中的层级

                 CONNECT_BY_ROOT(t.comment_id) fatherCommentID --首条评论的id

            from dbread.t_usercomment t

           WHERE t.top_target_type not in

                 ('comic', 'comic_part', 'cartoon', 'cartoon_part')

             and t.target_type = 'comment'

             and t.add_time >= date '2021-6-1'

             and t.add_time < date '2021-6-10'

           START with t.target_type != 'comment'

                  and t.comment_id is not null

          CONNECT by PRIOR t.comment_id = t.target_id

           ) t

   where exists

   (select 1

            from dbread.t_usercomment tmp1

           where t.device_id = tmp1.device_id

             and trunc(t.add_time) = trunc(tmp1.add_time)

             and tmp1.add_time >= date '2021-6-1'

             and tmp1.add_time < date '2021-6-10')),

--评论回复数

commentReply as

 (select t.fatherCommentID, count(1) replyCount

    from childComment t

  --where condition

   group by t.fatherCommentID)

--最终结果

select t.add_time 发布时间,

       t.comm_content 评论内容,

       t.productType 产品类别,

       nvl(t1.replyCount, 0) 评论回复数,

       nvl(t2.praiseCount, 0) 评论获赞数

  from fatherComment t

  left join commentReply t1

    on t.comment_id = t1.fatherCommentID

  left join (select t.target_id, count(1) praiseCount

               from dbread.t_userPraise t

              where t.oper_type in ('01', '03', '04')

                and t.target_type = 'comment'

                and t.add_time >= date '2021-6-1'

                and t.add_time < date '2021-6-10'

              group by t.target_id) t2

    on t.comment_id = t2.target_id;

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,332评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,508评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,812评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,607评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,728评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,919评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,071评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,802评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,256评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,576评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,712评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,389评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,032评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,798评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,026评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,473评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,606评论 2 350

推荐阅读更多精彩内容

  • 最近忙的不行本地安装nacos ,它既是注册中心,又是配置中心 默认端口8848(珠穆朗玛峰的高度)下载安装自行百...
    寂寞旅行阅读 964评论 0 0
  • If you’re unhappy at work, I have to ask: Why do you expe...
    春生阁阅读 315评论 0 1
  • 新的旧作品,黑白漫画《庸人之路》。本想着画的更厉害的时候再完成它,仔细想想,不画根本没办法进步,,全部101p。应...
    八头充电器阅读 645评论 2 3
  • 我是黑夜里大雨纷飞的人啊 1 “又到一年六月,有人笑有人哭,有人欢乐有人忧愁,有人惊喜有人失落,有的觉得收获满满有...
    陌忘宇阅读 8,531评论 28 53
  • 人工智能是什么?什么是人工智能?人工智能是未来发展的必然趋势吗?以后人工智能技术真的能达到电影里机器人的智能水平吗...
    ZLLZ阅读 3,767评论 0 5