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 ...
随机推荐
- 关于CCSprite不能及时显示的问题
今天在利用AFNetworking做网络请求时总是能看到添加的CCSprite精灵总是延迟一会才显示,google了半天没有找到答案, 考虑到CCSprite要被渲染才能显示,于是直接在场景中的CCL ...
- 洛谷 P1029 最大公约数和最小公倍数问题 Label:Water&&非学习区警告
题目描述 输入二个正整数x0,y0(2<=x0<100000,2<=y0<=1000000),求出满足下列条件的P,Q的个数 条件: 1.P,Q是正整数 2.要求P,Q以x0为 ...
- [Cocos2D-x For WP8]CocosDenshion音频播放
Cocos2D-x的音频分为长时间的背景音乐和短的音效两种,我们可以通过SimpleAudioEngine::sharedEngine()方法来获取音频播放的引擎,然后调用对音频相关的操作方法就可以了 ...
- 【noiOJ】p7914(..)
08:不重复地输出数 查看 提交 统计 提问 总时间限制: 1000ms 内存限制: 65536kB 描述 输入n个数,从小到大将它们输出,重复的数只输出一次.保证不同的数不超过500个. 输入 ...
- 使用SQLAlchemy对Firebird数据库进行操作
来这个公司已经一周了,度过了开始的无聊日子准备正式准备做点东西了,这几天接触了一下文件数据库InterBase,尝试在Ubuntu上连接其开源版本Firebird,因为公司使用的是SQLAlchemy ...
- 主席树+启发式合并(LT) BZOJ3123
好久没做题了,写道SBT又RE又T 查询:主席树裸题. 修改:对于两个树合并重建小的树. 注意fa[x][i]重新计算时要清空 #include<cstdio> #include<c ...
- 你用java的swing可以做出这么炫的mp3播放器吗?
这个mp3播放器是基于java的swing编写的,我认为界面还是可以拿出来和大家看一看评一评. 先说说创作的初衷,由于前段时间工作不是很忙,与其闲着,还不如找一些东西来给自己捣腾捣腾,在 之前写的 j ...
- js小效果-轮播图
<!DOCTYPE html><html><head lang="en"> <meta charset="UTF-8" ...
- MySQL连接池
1. using System; using System.Collections; using MySql.Data.MySqlClient; namespace Helper { /// < ...
- 转:DataGridView列的宽度、行的高度自动调整
注意:DataGridView控件是从.NET Framework 2.0版本开始追加的. 介绍一下DataGridView列的宽度和行的高度,根据单元格或Header的内容(一般是内容全部被表示)自 ...