Oracle的Connect By理解

connect by中的条件就表示了父子之间的连接关系 比如 connect by id=prior pid,但如果connect by中的条件没有表示记录之间的父子关系那会出现什么情况?

常见的,connect by会在构造序列的时候使用
select rownum from dual connect by rownum<xxx
代替早期版本的
select rownum from all_objects where rownum <xxx

我们注意到,dual是一个只有一条记录的表,如果表有多条记录,将会怎样?

下面开始实验

CREATE TABLE T(ID VARCHAR2(1 BYTE));

INSERT INTO T ( ID ) VALUES ( ‘A‘);
INSERT INTO T ( ID ) VALUES ( ‘B‘);
INSERT INTO T ( ID ) VALUES ( ‘C‘);
COMMIT;

SQL> select id,level from t connect by level<2;
I LEVEL
- ----------
A 1
B 1
C 1
SQL> select id,level from t connect by level<3;
I LEVEL
- ----------
A 1
A 2
B 2
C 2
B 1
A 2
B 2
C 2
C 1
A 2
B 2
C 2
已选择12行。
SQL> select id,level from t connect by level<4;
I LEVEL
- ----------
A 1
A 2
A 3
B 3
C 3
B 2
A 3
B 3
C 3
C 2
A 3
B 3
C 3
B 1
A 2
A 3
B 3
C 3
B 2
A 3
B 3
C 3
C 2
A 3
B 3
C 3
C 1
A 2
A 3
B 3
C 3
B 2
A 3
B 3
C 3
C 2
A 3
B 3
C 3
已选择39行。

我们很快可以找到其中的规律,假设表中有N条记录, 则记F(N,l)为select id,level from t connect by level<l 的结果集数目
那么,
F(N,1)=N
F(N,l) = F(N,l-1)*N+N

于是可以总结出
F(N,l)=∑power(N,p), p取值为[1,l)

要解释,也很容易:当连接条件不能限制记录之间的关系时每一条记录都可以作为自己或者其他记录的叶子
如下所示:
A          1
A          2
A          3
B          3
C          3
B          2
A          3
B          3
C          3
C          2
A          3
B          3
C          3
在这里,我们看到的是Oracle采用了深度优先的算法

我们接着看一个例子,看看在SQL中通过connect by如何将任意一个整数(不要太大就行)拆分为若干个power(2,n)的和的方法。
先构造测试数据:

create table ba(n number);

insert into ba select 5*rownum from dual connect by rownum<5;

commit;

select * from ba;N-------5101520

一个得出结果的简单的SQL为

  1. select distinct a.n , level, bitand(a.n,power(2,level-1)) from ba a connect by level<=floor(log(2,n)+1)

这里为什么要加distinct?你可以尝试去掉distinct ,看看结果与保持distinct有多大差别。

然后我们先来看,如果只对其中的一条记录进行操作,那么加不加distinct,结果是否是一样的?比如我们只看第一条记录5的拆分结果

select distinct a.n , level, bitand(a.n,power(2,level-1)) from (select * from ba where rownum=1) a connect by level<=floor(log(2,n)+1);

结果为:

  1. N    LEVEL    BITAND(A.N,POWER(2,LEVEL-1))
  2. ----------------------------------------------------------------
  3. 5    1             1
  4. 5    2             0
  5. 5    3             4

去掉distinct的sql为

  1. select a.n , level, bitand(a.n,power(2,level-1)) from (select * from ba where rownum=1) a connect by level<=floor(log(2,n)+1);

输出结果,自己运行一下看看。然后你就该思考了,为什么你看到的结果会是这样???

这里不做过多解释,做完上面的实验,然后结合1楼中所说的,我想你应该就能明白了。

事实上我们有更好的办法来处理:

with a as (select n, floor(log(2,n)+1) lc from ba)

select a.n, bitand(a.n,power(2,b.rn-1)) from a, 

(select rownum rn from

        (select max(lc) mlc from a) 

        connect by level<=mlc

)b

where rn<=a.lc

order by 1,2

内层SQL先取得所有记录中可拆分出来的power(2,n)中的n最大可能是多少,然后由此构造出序列,最后再做一次关联查询,

用限制条件rn<=a.lc限制住每个N中可拆分出来的power(2,n)中的n的最大值,由此可以高效得出结果。

上例实质上与 对多记录按各自指定次数重复 的性质是一样的。

简单总结:
对单记录/单条数据使用connect by,没问题
但对多条记录使用connect by,就会碰到问题,千万要注意。

elect rownum,
       level,
       sys_connect_by_path(id, ‘,‘) path,
       id,
       connect_by_isleaf isleaf
  from t
connect by nocycle level < 2
order by rownum, level, path;

select rownum,
       level,
       sys_connect_by_path(id, ‘,‘) path,
       id,
       connect_by_isleaf isleaf
  from t
connect by nocycle level < 3
order by rownum, level, path;

select rownum,
       level,
       sys_connect_by_path(id, ‘,‘) path,
       id,
       connect_by_isleaf isleaf
  from t
connect by nocycle level < 4
order by rownum, level, path;

下面是执行结果:
CHENCH@orcl> select rownum,
  2         level,
  3         sys_connect_by_path(id, ‘,‘) path,
  4         id,
  5         connect_by_isleaf isleaf
  6    from t
  7  connect by nocycle level < 2
  8   order by rownum, level, path;

    ROWNUM      LEVEL PATH       ID     ISLEAF
---------- ---------- ---------- -- ----------
         1          1 ,A         A           1
         2          1 ,B         B           1
         3          1 ,C         C           1

Elapsed: 00:00:00.01
CHENCH@orcl>
CHENCH@orcl> select rownum,
  2         level,
  3         sys_connect_by_path(id, ‘,‘) path,
  4         id,
  5         connect_by_isleaf isleaf
  6    from t
  7  connect by nocycle level < 3
  8   order by rownum, level, path;

    ROWNUM      LEVEL PATH       ID     ISLEAF
---------- ---------- ---------- -- ----------
         1          1 ,A         A           0
         2          2 ,A,A       A           1
         3          2 ,A,B       B           1
         4          2 ,A,C       C           1
         5          1 ,B         B           0
         6          2 ,B,A       A           1
         7          2 ,B,B       B           1
         8          2 ,B,C       C           1
         9          1 ,C         C           0
        10          2 ,C,A       A           1
        11          2 ,C,B       B           1

    ROWNUM      LEVEL PATH       ID     ISLEAF
---------- ---------- ---------- -- ----------
        12          2 ,C,C       C           1

12 rows selected.

Elapsed: 00:00:00.01
CHENCH@orcl>
CHENCH@orcl> select rownum,
  2         level,
  3         sys_connect_by_path(id, ‘,‘) path,
  4         id,
  5         connect_by_isleaf isleaf
  6    from t
  7  connect by nocycle level < 4
  8   order by rownum, level, path;

    ROWNUM      LEVEL PATH       ID     ISLEAF
---------- ---------- ---------- -- ----------
         1          1 ,A         A           0
         2          2 ,A,A       A           0
         3          3 ,A,A,A     A           1
         4          3 ,A,A,B     B           1
         5          3 ,A,A,C     C           1
         6          2 ,A,B       B           0
         7          3 ,A,B,A     A           1
         8          3 ,A,B,B     B           1
         9          3 ,A,B,C     C           1
        10          2 ,A,C       C           0
        11          3 ,A,C,A     A           1

    ROWNUM      LEVEL PATH       ID     ISLEAF
---------- ---------- ---------- -- ----------
        12          3 ,A,C,B     B           1
        13          3 ,A,C,C     C           1
        14          1 ,B         B           0
        15          2 ,B,A       A           0
        16          3 ,B,A,A     A           1
        17          3 ,B,A,B     B           1
        18          3 ,B,A,C     C           1
        19          2 ,B,B       B           0
        20          3 ,B,B,A     A           1
        21          3 ,B,B,B     B           1
        22          3 ,B,B,C     C           1

    ROWNUM      LEVEL PATH       ID     ISLEAF
---------- ---------- ---------- -- ----------
        23          2 ,B,C       C           0
        24          3 ,B,C,A     A           1
        25          3 ,B,C,B     B           1
        26          3 ,B,C,C     C           1
        27          1 ,C         C           0
        28          2 ,C,A       A           0
        29          3 ,C,A,A     A           1
        30          3 ,C,A,B     B           1
        31          3 ,C,A,C     C           1
        32          2 ,C,B       B           0
        33          3 ,C,B,A     A           1

    ROWNUM      LEVEL PATH       ID     ISLEAF
---------- ---------- ---------- -- ----------
        34          3 ,C,B,B     B           1
        35          3 ,C,B,C     C           1
        36          2 ,C,C       C           0
        37          3 ,C,C,A     A           1
        38          3 ,C,C,B     B           1
        39          3 ,C,C,C     C           1

39 rows selected.

Elapsed: 00:00:00.04
关键是 connect by 后面不管是level 还是 rownum都是在查询结果集内作的限制

SQL> with t as (
  2  select 1 from dual
  3  union all
  4  select 2 from dual
  5  union all
  6  select 3 from dual)
  7  select * from t connect by rownum < 5;

         1
----------
         1
         1
         1
         1
         2
         3

已选择6行。

SQL> with t as (select 1 from dual)
  2  select * from t connect by rownum < 5;

         1
----------
         1
         1
         1
         1

已选择4行。
with a as (
    select 5 as n from dual
    union all
    select 10 from dual
    union all
    select 15 from dual
    union all
    select 20 from dual
    )
select  distinct a.n , level, bitand(a.n,power(2,level-1)) from a connect by level<=floor(log(2,n)+1);

SQL> with a as (
  2      select 5 as n from dual
  3      union all
  4      select 10 from dual
  5      union all
  6      select 15 from dual
  7      union all
  8      select 20 from dual
  9     )
 10  select  distinct a.n , level, bitand(a.n,power(2,level-1)) from a connect by level<=floor(log(2,n)+1);

         N      LEVEL BITAND(A.N,POWER(2,LEVEL-1))
---------- ---------- ----------------------------
        10          4                            8
        15          2                            2
        20          2                            0
        20          4                            0
        15          3                            4
         5          1                            1
        10          3                            0
        10          1                            0
        20          3                            4
         5          2                            0
        20          5                           16
        10          2                            2
         5          3                            4
        15          4                            8
        15          1                            1
        20          1                            0

已选择16行。
SQL> with a as (
  2          select 5 as n from dual
  3          union all
  4          select 10 from dual
  5          union all
  6          select 15 from dual
  7          union all
  8          select 20 from dual
  9         )
 10     select  distinct a.n , level, bitand(a.n,power(2,level-1)) from (select * from a where rownum=1) a connect by level<=floor(log(2,n)+1);

         N      LEVEL BITAND(A.N,POWER(2,LEVEL-1))
---------- ---------- ----------------------------
         5          1                            1
         5          2                            0
         5          3                            4

已选择3行。

SQL> with a as (
  2          select 5 as n from dual
  3          union all
  4          select 10 from dual
  5          union all
  6          select 15 from dual
  7          union all
  8          select 20 from dual
  9         )
 10     select  a.n , level, bitand(a.n,power(2,level-1)) from (select * from a where rownum=1) a connect by level<=floor(log(2,n)+1);

         N      LEVEL BITAND(A.N,POWER(2,LEVEL-1))
---------- ---------- ----------------------------
         5          1                            1
         5          2                            0
         5          3                            4

已选择3行。
SQL>    with a as (
  2          select 5 as n from dual
  3          union all
  4          select 10 from dual
  5          union all
  6          select 15 from dual
  7          union all
  8          select 20 from dual
  9         )
 10     select * from a where a.n=5 connect by rownum<6;

         N
----------
         5
         5
         5
         5
         5
SQL>    with a as (
  2          select 5 as n from dual
  3          union all
  4          select 10 from dual
  5          union all
  6          select 15 from dual
  7          union all
  8          select 20 from dual
  9         )
 10     select * from a where rownum=1 connect by rownum<6;
ERROR:
ORA-30009: CONNECT BY 操作内存不足
 with a as (
      select 5 as n from dual
      union all
      select 10 from dual
      union all
      select 15 from dual
      union all
      select 20 from dual
     )
 select * from a where a.n=5 connect by level<6;
5
5
5
5
5
5
5
5
5
5

已选择341行。
时间: 2024-10-09 05:38:38

Oracle的Connect By理解的相关文章

oracle中 connect by prior 递归算法 -- 理解

http://blog.163.com/xxciof/blog/static/7978132720095193113752/ oracle中 connect by prior 递归算法 Oracle中start with...connect by prior子句用法 connect by 是结构化查询中用到的,其基本语法是: select ... from tablename start with 条件1 connect by 条件2 where 条件3; 例: select * from ta

oracle使用connect by进行级联查询 树型菜单

Oracle使用connect by进行级联查询 树型菜单(转) connect by可以用于级联查询,常用于对具有树状结构的记录查询某一节点的所有子孙节点或所有祖辈节点. 来看一个示例,现假设我们拥有一个菜单表t_menu,其中只有三个字段:id.name和parent_id.它们是具有父子关系的,最顶级的菜单对应的parent_id为0.现假设我们拥有如下记录: id name parent_id 1 菜单01 0 2 菜单02 0 3 菜单03 0 4 菜单0101 1 5 菜单0102

oracle中 connect by prior 递归算法

http://blog.163.com/xxciof/blog/static/7978132720095193113752/ oracle中 connect by prior 递归算法 Oracle中start with...connect by prior子句用法 connect by 是结构化查询中用到的,其基本语法是: select ... from tablename start with 条件1 connect by 条件2 where 条件3; 例: select * from ta

通过阅读Oracle Enterprise Asset Management User Guide,我对Oracle eAM的初步理解

通过阅读Oracle Enterprise Asset Management User Guide,我对Oracle eAM的初步理解 Oracle eAM是Oracle EBS套件的一部分,解决资产密集的组织的综合的和常规的设备维护需求.在设备层面追踪所有的维护成本和工作历史,来衡量绩效和最优化维护操作. eAM为组织提供了工具给资产和可重建的库存物料创建和应用维护程序.eAM让用户可以最大化地计划和安排维护活动,同时对组织的运作或生产中断最小.重要的是,它能提高资源有效性,增强维护质量,跟踪

oracle中connect by语句的优化

很多应用中都会有类似组织机构的表,组织机构的表又通常是典型的层次结构(没有循环节点).于是通过组织控制数据权限的时候,许多人都喜欢通过connect by获得组织信息,然后再过滤目标数据. 在有些情况下,这样写并没有什么问题,但有些情况下,这个就是一个大问题. 归根结底,这是connect by特性导致的,oracle无法知道connect by之后到底返回多少数据,所以有可能采取一些你所不期望的算法,结果自然不是你所期望的---非常慢. 下面,我就讨论在12.1.0.2中如果遇到这样的语句应该

oracle中Connect By用法介绍

为解决oracle中自连接查询不适合操作大表的情况,采用connect by 方式实现.oracle中可以用START WITH...CONNECT BY PRIOR子句实现递归查询,connect by 在结构化查询中应用. 基本语法: select ... from <TableName> where <Conditional1> connect by <Conditional2> start with <Conditional3> connect by

oracle数据库基础概念理解

1.oracle数据库服务器企业版安装后会默认安装一个数据库实例,安装时有4个管理员账号,安装时设置相同的用户名及口令. 2.数据库实例安装好后,我们可以在其上创建多个表空间,接着可以创建新用户,给新用户分配connect,resource,dba权限,给用户分配所属的表空间,这样不同的用户,在不同的表空间内工作,互不影响.可以为每一个项目数据库建立一个表空间,这里的表空间有点像mysql里的数据库. 3.我们也可以使用dbca(数据库创建助手),新建另外的数据库实例,并且指定新的该数据库的4个

oracle中 connect by prior 递归查询

Oracle中start with...connect by prior子句用法 connect by 是结构化查询中用到的,其基本语法是: select ... from tablename start with 条件1 connect by 条件2 where 条件3; 例: select * from table start with org_id = 'HBHqfWGWPy' connect by prior org_id = parent_id; 简单说来是将一个树状结构存储在一张表里

【每日积累】-oracle之connect by 002

1. hierarchical query 语义分析: 2. hierarchical query 脚本测试: ---删除已存在表 drop table test;-- Create tablecreate table TEST(  orgno  NUMBER(10) not null,  deptno NUMBER(10),  deptnm VARCHAR2(20));---insert dateinsert into test values(1,0,'abc');insert into te