Oracle之connect by 之练习篇

说明:
1. START WITH:告诉系统以哪个节点作为根结点开始查找并构造结果集,该节点即为返回记录中的最高节点。

2. CONNECT_BY_ROOT 返回当前节点的最顶端节点
3. CONNECT_BY_ISLEAF 判断是否为叶子节点,如果这个节点下面有子节点,则不为叶子节点
4. LEVEL 伪列表示节点深度,从1开始
5. SYS_CONNECT_BY_PATH函数显示详细路径

建表

createtable TREETABLE

(

 ID        VARCHAR2(10),

 NAME      VARCHAR2(10),

 PARENT_ID VARCHAR2(10)

)

插入数据

insert into TREETABLE (ID, NAME, PARENT_ID)

values ('100000', '根节点', '');

insert into TREETABLE (ID, NAME, PARENT_ID)

values ('100100', '节点1', '100000');

insert into TREETABLE (ID, NAME, PARENT_ID)

values ('100101', '节点3','100100');

insert into TREETABLE (ID, NAME, PARENT_ID)

values ('100102', '节点4','100100');

insert into TREETABLE (ID, NAME, PARENT_ID)

values ('100200', '节点2','100000');

insert into TREETABLE (ID, NAME, PARENT_ID)

values ('100201', '节点5','100200');

insert into TREETABLE (ID, NAME, PARENT_ID)

values ('100202', '节点6','100200');

查询数据

select T.*

 from TREETABLE T

 orderby T.ID

ID

NAME

PARENT_ID

100000

根节点


100100

节点1

100000

100101

节点3

100100

100102

节点4

100100

100200

节点2

100000

100201

节点5

100200

100202

节点6

100200

 

1、从根节点开始从上到下遍历访问

--注意:(1)、ISLEAFLEVEL属性的值

--2)、可能对应一个或多个分支

select CONNECT_BY_ROOT T.ID "ROOT"

       ,T.PARENT_ID

       ,T.ID

       ,LPAD('*', 10 * (level - 1), '*') || T.NAME asname

       ,CONNECT_BY_ISLEAF "ISLEAF"

       ,level

 from TREETABLE T

 startwith T.ID = '100000'

connectby T.PARENT_ID= prior T.ID

ROOT

PARENT_ID

ID

NAME

ISLEAF

LEVEL

100000


100000

根节点

0

1

100000

100000

100100

**********节点1

0

2

100000

100100

100101

********************节点3

1

3

100000

100100

100102

********************节点4

1

3

100000

100000

100200

**********节点2

0

2

100000

100200

100201

********************节点5

1

3

100000

100200

100202

********************节点6

1

3

 

2、从节点100100开始从上到下遍历访问

select CONNECT_BY_ROOT T.ID "ROOT"

       ,T.PARENT_ID

       ,T.ID

       ,LPAD('*', 10 * (level - 1), '*') || T.NAME asname

       ,CONNECT_BY_ISLEAF "ISLEAF"

       ,level

 from TREETABLE T

 startwith T.ID = '100100'

connectby T.PARENT_ID= prior T.ID

ROOT

PARENT_ID

ID

NAME

ISLEAF

LEVEL

100100

100000

100100

节点1

0

1

100100

100100

100101

**********节点3

1

2

100100

100100

100102

**********节点4

1

2

 

3、不指定START WITH

--如果不指定start with,则oracle会把所有的节点都当成根节点分别往下遍历。

select CONNECT_BY_ROOT T.ID "ROOT"

       ,T.PARENT_ID

       ,T.ID

       ,LPAD('*', 10 * (level - 1), '*') || T.NAME asname

       ,CONNECT_BY_ISLEAF "ISLEAF"

       ,level

 from TREETABLE T

connectby T.PARENT_ID= prior T.ID

ROOT

PARENT_ID

ID

NAME

ISLEAF

LEVEL

100100

100000

100100

节点1

0

1

100100

100100

100101

**********节点3

1

2

100100

100100

100102

**********节点4

1

2

100200

100000

100200

节点2

0

1

100200

100200

100201

**********节点5

1

2

100200

100200

100202

**********节点6

1

2

100101

100100

100101

节点3

1

1

100102

100100

100102

节点4

1

1

100201

100200

100201

节点5

1

1

100202

100200

100202

节点6

1

1

100000


100000

根节点

0

1

100000

100000

100100

**********节点1

0

2

100000

100100

100101

********************节点3

1

3

100000

100100

100102

********************节点4

1

3

100000

100000

100200

**********节点2

0

2

100000

100200

100201

********************节点5

1

3

100000

100200

100202

********************节点6

1

3

 

4、从节点100101开始从下到上访问到根节点

--注意:(1)、此时原来的根节点(100000)的ISLEAF1,而原来的叶子节点(100102)的ISLEAF0

--2)、LEVEL层次也发生了变化

--3)、这种情况下只可能有一个分支

select CONNECT_BY_ROOT T.ID "ROOT"

       ,T.PARENT_ID

       ,T.ID

       ,LPAD('*', 10 * (level - 1), '*') || T.NAME asname

       ,CONNECT_BY_ISLEAF "ISLEAF"

       ,level

 from TREETABLE T

 startwith T.ID = '100102'

connectby T.ID = prior T.PARENT_ID

ROOT

PARENT_ID

ID

NAME

ISLEAF

LEVEL

100102

100100

100102

节点4

0

1

100102

100000

100100

**********节点1

0

2

100102


100000

********************根节点

1

3

 

4的变形

select CONNECT_BY_ROOT T.ID "ROOT"

       ,T.PARENT_ID

       ,T.ID

       ,LPAD('*', 10 * (5 - level), '*') || T.NAME asname

       ,CONNECT_BY_ISLEAF "ISLEAF"

       ,level

 from TREETABLE T

 startwith T.ID = '100102'

connectby T.ID = prior T.PARENT_ID

 

ROOT

PARENT_ID

ID

NAME

ISLEAF

LEVEL

100102

100100

100102

****************************************节点4

0

1

100102

100000

100100

******************************节点1

0

2

100102


100000

********************根节点

1

3

 

 

5、在1sql中加入where level进行过滤

--可以看到,得到的结果的level值都是<=2

select CONNECT_BY_ROOT T.ID "ROOT"

       ,T.PARENT_ID

       ,T.ID

       ,LPAD('*', 10 * (level - 1), '*') || T.NAME asname

       ,CONNECT_BY_ISLEAF "ISLEAF"

       ,level

 from TREETABLE T

 wherelevel <=2

 startwith T.ID = '100000'

connectby T.PARENT_ID= prior T.ID

 

ROOT

PARENT_ID

ID

NAME

ISLEAF

LEVEL

100000


100000

根节点

0

1

100000

100000

100100

**********节点1

0

2

100000

100000

100200

**********节点2

0

2

 

过滤个体和整个分支

6、在1sql中加入where 过滤个体(从根到叶的遍历)

--可以看到,在结果中没有节点1100100),但是他的子孙还在

--其实通过了解sql的执行顺序也不难理解这样的过滤个体

select CONNECT_BY_ROOT T.ID "ROOT"

       ,T.PARENT_ID

       ,T.ID

       ,LPAD('*', 10 * (level - 1), '*') || T.NAME asname

       ,CONNECT_BY_ISLEAF "ISLEAF"

       ,level

 from TREETABLE T

 where t.id != '100100'

 startwith T.ID = '100000'

connectby T.PARENT_ID= prior T.ID

ROOT

PARENT_ID

ID

NAME

ISLEAF

LEVEL

100000


100000

根节点

0

1

100000

100100

100101

********************节点3

1

3

100000

100100

100102

********************节点4

1

3

100000

100000

100200

**********节点2

0

2

100000

100200

100201

********************节点5

1

3

100000

100200

100202

********************节点6

1

3

 

7、在4sql中加入where过滤个体(从叶到根的遍历)

select CONNECT_BY_ROOT T.ID "ROOT"

       ,T.PARENT_ID

       ,T.ID

       ,LPAD('*', 10 * (level - 1), '*') || T.NAME asname

       ,CONNECT_BY_ISLEAF "ISLEAF"

       ,level

 from TREETABLE T

 where t.id != '100100'

 startwith T.ID = '100102'

connectby T.ID = prior T.PARENT_ID

 

ROOT

PARENT_ID

ID

NAME

ISLEAF

LEVEL

100102

100100

100102

节点4

0

1

100102


100000

********************根节点

1

3

 

8、在1sql中用connect by 过滤整个分支(从根到叶的遍历)

--使用connect by 子句不仅排除所提到的节点,而且排除他的所有子节点。

--connect by 子句实际上是对树结构进行追踪。如果没有100100节点,那么也不会有他的子节点

select CONNECT_BY_ROOT T.ID "ROOT"

       ,T.PARENT_ID

       ,T.ID

       ,LPAD('*', 10 * (level - 1), '*') || T.NAME asname

       ,CONNECT_BY_ISLEAF "ISLEAF"

       ,level

 from TREETABLE T

 startwith T.ID = '100000'

connectby T.PARENT_ID= prior T.ID

and t.id != '100100'

 

ROOT

PARENT_ID

ID

NAME

ISLEAF

LEVEL

100000


100000

根节点

0

1

100000

100000

100200

**********节点2

0

2

100000

100200

100201

********************节点5

1

3

100000

100200

100202

********************节点6

1

3

 

 

9、在4sql中用connect by 过滤整个分支(从叶到根的遍历)

select CONNECT_BY_ROOT T.ID "ROOT"

       ,T.PARENT_ID

       ,T.ID

       ,LPAD('*', 20 * (level - 1), '*') || T.NAME asname

       ,CONNECT_BY_ISLEAF "ISLEAF"

       ,level

 from TREETABLE T

 startwith T.ID = '100202'

connectby T.ID = prior T.PARENT_ID

and t.id != '100000'

 

ROOT

PARENT_ID

ID

NAME

ISLEAF

LEVEL

100202

100200

100202

节点6

0

1

100202

100000

100200

**********节点2

1

2

 

 

跳出循环

--如果我们把根节点的parent_id修改成100102,即在树中形成了一个环

--此时,如果执行1sql,会发现有错误 '用户数据中的connect by 循环'

--当您获得像这样的一条错误消息时,您可以使用 CONNECT_BY_ISCYCLE 虚拟列来确定引起问题的行的位置。

--要做到这一点,您还必须添加 NOCYCLE 关键字到 CONNECT BY 子句中,防止数据库进入层次结构中的任何循环

select CONNECT_BY_ROOT T.ID "ROOT"

       ,T.PARENT_ID

       ,T.ID

       ,LPAD('*', 10 * (level - 1), '*') || T.NAME asname

       ,CONNECT_BY_ISLEAF "ISLEAF"

       ,level

       ,CONNECT_BY_ISCYCLE "ISCYCLE"

 from TREETABLE T

 startwith T.ID = '100000'

connectbyNOCYCLE T.PARENT_ID = prior T.ID

 

ROOT

PARENT_ID

ID

NAME

ISLEAF

LEVEL

ISCYCLE

100000

100102

100000

根节点

0

1

0

100000

100000

100100

**********节点1

0

2

0

100000

100100

100101

********************节点3

1

3

0

100000

100100

100102

********************节点4

1

3

1

100000

100000

100200

**********节点2

0

2

0

100000

100200

100201

********************节点5

1

3

0

100000

100200

100202

********************节点6

1

3

0

 

 

基本规则

使用connect by start with来创建类似于树的报表并不难,只要遵循以下基本规则即可

1、使用connect by 时各子句的顺序为:

1select

2from

3where

4start with

5connect by

6order by

2prior强制报表的顺序变为从根到叶(如果prior列是父辈)或从叶到根(如果prior列是后代)

3、虽然where子句可以从树中排除个体,但不排除他们的子孙(或者祖先,如果是从叶到根的遍历)

4connect by中的条件(尤其是不等于)可以排除个体和它所有的子孙(或祖先,取决于怎样跟踪树)

5connect by不能和where子句中的表连接使用

你可能感兴趣的:(Oracle之connect by 之练习篇)