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 ...
随机推荐
- BZOJ3566 : [SHOI2014]概率充电器
选个根把无根树转化成有根树, 设f[i]表示i不通电的概率 则 答案为对于枚举树根root进行DP后1-f[root]的和 直接算是O(n^2)的,但是n有500000,所以不能过. 对于这样一棵以1 ...
- echarts.js 做图表的插件
<scripttype="text/javascript"src="{uiurl()}echarts/echarts.js"></script ...
- 隐式调用 Intent 大全, 很全
http://ming-fanglin.iteye.com/blog/1061312 //调用浏览器 Uri uri = Uri.parse(""); Intent it = n ...
- 求1+2+……+n(位运算)
求1+2+3+...+n,要求不能使用乘除法.for.while.if.else.switch.case等关键字及条件判断语句(A?B:C). 我发现网上的做法都很神,各种理由编译的巧妙办法,就能间接 ...
- lsof用法简介
lsof:一个功能强大的命令 lsof命令的原始功能是列出打开的文件的进程,但LINUX下,所有的设备都是以文件的行式存在的,所以,lsof的功能很强大! [root@limt01 ~]# lsof ...
- dynamic 是什么
dynamic是c# 4.0新增的类型,可以修饰类,对象,属性,索引器,方法返回值等. class ExampleClass { // A dynamic field. static dynamic ...
- 设置 tableview 的背景颜色,总是不生效
1.只设置了背景图片,却忘记了取消掉 cell 的背景颜色(可以通过层次结构来观察) UIImageView *bgView = [[UIImageView alloc]initWithFrame:s ...
- signal(SIGPIPE, SIG_IGN)
文章来源:http://blog.163.com/niuxiangshan@126/blog/static/170596595201221942952676/ 当服务器close一个连接时,若cl ...
- 全选,不选,反选 jquery
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- concat,reverse
1.concat 连接,拼接 <script> var arr1=[1,2,3]; var arr2=[4,5,6]; var arr3=[7,8,9]; alert(arr1.conca ...