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
-------
5
10
15
20
一个得出结果的简单的SQL为
- 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);
结果为:
- N LEVEL BITAND(A.N,POWER(2,LEVEL-1))
- ----------------------------------------------------------------
- 5 1 1
- 5 2 0
- 5 3 4
去掉distinct的sql为
- 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行。
Oracle的Connect By理解的更多相关文章
- oracle中 connect by prior 递归算法 -- 理解
oracle中 connect by prior 递归算法 -- 理解 http://blog.163.com/xxciof/blog/static/7978132720095193113752/ ...
- oracle使用connect by进行级联查询 树型菜单
Oracle使用connect by进行级联查询 树型菜单(转) connect by可以用于级联查询,常用于对具有树状结构的记录查询某一节点的所有子孙节点或所有祖辈节点. 来看一个示例,现假设我们拥 ...
- 12C 连接方式和 Oracle Easy Connect Naming method
1.12C 连接方式 PDB is not an instance, so using SID in the connection string will not work. When the dat ...
- mysql实现ORACLE的connect by prior父子递归查询
oracle中有connect by prior ,可以实现父子递归查询.而mysql中没有这种功能,但我们可以变通实现. 比如一个表: Table Name: tb_Tree Id | Parent ...
- oracle 分页(rownum的理解) 以及 树节点的查询
1:什么是rownum, rownum的生成, rownum相关的符号操作 Rownum是oracle生成结果集时得到的一个伪列, 按照读出行的顺序, 第一条rownum=1, 第二条=2. 对于 O ...
- ORACLE中CONNECT BY...START WITH...的使用
源: https://docs.oracle.com/cd/B19306_01/server.102/b14200/queries003.htm http://www.cnblogs.com/baiy ...
- oracle中connect by语句的优化
很多应用中都会有类似组织机构的表,组织机构的表又通常是典型的层次结构(没有循环节点).于是通过组织控制数据权限的时候,许多人都喜欢通过connect by获得组织信息,然后再过滤目标数据. 在有些情况 ...
- ORACLE的CONNECT和RESOURCE角色权限
最近在处理数据库的用户权限问题,之前惯性思维,觉得给用户授权RESOURCE权限之后,用户的一般权限都会有,等到发现用户有RESOURCE角色,却没有创建视图的权限之后,才发现这部分还是一知半解啊,所 ...
- oracle中 connect by prior 递归算法
Oracle中start with...connect by prior子句用法 connect by 是结构化查询中用到的,其基本语法是: select ... from tablename sta ...
随机推荐
- BZOJ2061 : Country
记忆化搜索,设$f[i][j]$表示符号$i$一开始kmp指针为$j$,中间匹配了多少次,$g[i][j]$则表示匹配结束后kmp指针的位置. 时间复杂度$O(nl^2)$. #include< ...
- 熟悉熟悉常用的几个算法用JS的实现
(1)数组去重 原理:定义一个对象obj,然后把数组元素作为obj的属性名,利用属性名是否重复进行判重 1 var unique = function(arr){ 2 let obj = {}; 3 ...
- CentOS6.4 增加一个SFTP上传的用户
#创建sftp组 groupadd sftp #创建一个用户dsideal useradd -g sftp -s /bin/false dsideal #设置dsideal用户的密码 passwd d ...
- CF 71C. Round Table Knights
题目链接 很多小的细节都没想到... #include <cstdio> #include <cstring> #include <iostream> #inclu ...
- CF 2B.The least round way
题目链接 很久以前就见过此题,以前看了题解,然后今天写了写,写的真搓. #include <cstdio> #include <cstring> #include <st ...
- HDU 4758 Walk Through Squares(AC自动机+DP)
题目链接 难得出一个AC自动机,我还没做到这个题呢...这题思路不难想,小小的状压出一维来,不过,D和R,让我wa死了,AC自动机,还得刷啊... #include<iostream> # ...
- 一、午夜倒数《苹果iOS实例编程入门教程》
该app为应用的功能为计算离午夜12:00点的剩余时间 现版本 SDK 8.4 Xcode 运行Xcode 选择 Create a new Xcode project ->Single View ...
- Compound Words
题目链接:http://acm.hust.edu.cn/vjudge/contest/view.action?cid=91209#problem/C 题意: 有一堆按照字典序排好的字符串,问你有多 ...
- 利用MetaWeblog API实现XMLRPC写博客功能
Windows Live Writer是一款小巧的写博客的工具,非常方便,甚至网上看到过有的评论称Live Writer是一款最不像微软产品的微软产品. Writer支持MSN Spaces以及Wor ...
- Repaint轨迹保留?(待处理,待编辑)
import java.awt.Color; import java.awt.Graphics; import javax.swing.JFrame; import javax.swing.JPane ...