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 ...
随机推荐
- js中eval详解,用Js的eval解析JSON中的注意点
先来说eval的用法,内容比较简单,熟悉的可以跳过eval函数接收一个参数s,如果s不是字符串,则直接返回s.否则执行s语句.如果s语句执行结果是一个值,则返回此值,否则返回undefined. 需要 ...
- 【CodeVS】 p1077 多源最短路
题目描述 Description 已知n个点(n<=100),给你n*n的方阵,a[i,j]表示从第i个点到第j个点的直接距离. 现在有Q个询问,每个询问两个正整数,a和b,让你求a到b之间的最 ...
- Android -- ImageView通过Bitmap得到网上的图片资源
1. 效果图
- MYSQL加锁的测验
存储引擎 支持的锁定级别 myisam 表级别 memory 表级别 inndb 行级别 bdb: 页级别 lock锁定类型 锁定方式 ...
- 在不知道json格式的情况下如何使用cjson进行解析
假设我们有一个json字符串,但是我们不知道这个json的组织方式,那么如何进行解析呢,下面就给一个小例子. 1.我们的json串如下: { "aStr": "aaaaa ...
- IIS7.0+部署ARR负载均衡
安装: 1. 安装IIS(需要附带相关的健康检查,需要原始的那个默认站点) 2. 安装ARR相关的文件 3. 安装好之后,IIS里会出现有Server Farms的节点,直接创建服务器. 站点对 ...
- JDBC学习笔记2
数据库数据更新操作statement接口下操作:[代码] import java.sql.DriverManager;import java.sql.SQLException; public clas ...
- [LintCode] Pow(x, n) 求x的n次方
Implement pow(x, n). Notice You don't need to care about the precision of your answer, it's acceptab ...
- scala - Map基础
Map 构造Map 不可变: val map = Map("sa" -> 1, "s" -> 2)map("sa") = 3 / ...
- webform FileUpload控件实例应用 上传图片
首先在根目录下建一个"images"文件: HTML: <form id="form1" runat="server"> < ...