connect by rownum及connect by level的内部执行原理及过程
来源:互联网 发布:java并发编程解决方案 编辑:程序博客网 时间:2024/06/06 03:00
来自兔子大神blog地址:http://www.itpub.net/thread-1570306-1-1.html
对于有N条记录的来说,如果没有递归条件,直接connect by level,先深度搜索,再广度,则
每个节点作为根节点,然后自身和其他节点为子节点,然后下个子节点还包括自身和其他节点,然后同样迭代
所以,总共记录数有N*2^0+N*2^1+......... 其中0,1....为level
则记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)
总记录数N,level层数P
结果集数:T=∑N^x(x=1...p)
比如,总记录数为3,层数为3
则结果集数:3^1 +3^2 + 3^3 = 3+9+27=39
SELECT rowid,a,b,level,rownum FROM test1 CONNECT BY level<=3;
对于记录数N,则第m层记录数为N^m
N=3,LEVEL<=1 s=N
LEVEL<=2 s=N^1+N^2
LEVEL<=3 s=N^1+N^2+N^3
...
LEVEL<=m s=N^1+N^2+N^3+....N^m
等比数列q=N,a1=N
s=N(1-N^m)/(1-N) 其中m为需要迭代的level最大值
dingjun123@ORADB> select * from t;
ID
----------
1
1
已选择2行。
已用时间: 00: 00: 00.04
dingjun123@ORADB> select rownum from t connect by rownum <= 2;
ROWNUM
----------
1
2
3
已选择3行。
已用时间: 00: 00: 00.01
connect by 的本质分析
执行下面两句:
select level,rownum from dual connect by level<=10;
select level,rownum from dual connect by rownum<=10;
两句显示的效果完全一样,
但是,如果select有2条或更多,效果就大不一样
select A.TABLE_NAME,level,rownum from (select * from USER_TABLES A WHERE ROWNUM<=2 ) A connect by level<=10; --有2046条
select A.TABLE_NAME, level,rownum from (select * from USER_TABLES WHERE ROWNUM<=2) A connect by rownum<=10 ; --有11条;
所以,想咨询专家 connect by level 和 connect by rownum 的本质区别;
列个关系列表,也许可以通过数学归纳法,得出其中规律
select 的记录数(m) connect by 层数(n) by level 的记录数 by rownum的记录数
1 10 10 10
2 10 2046 11
3 10 88572 12
4 10 1398100 13
by rownum的记录数 规律很明显: connect by 层数(n) +select 的记录数(m) -1;
by level 的记录数 的规律还没找出
--深刻理解connect by的原理,理解statr with,connect by,理解层次如何生成的
--理解connect by level和connect by rownum的区别,比如掌握level如何生成,rownum如何生成
--connect by level是先做递归,然后判断level是否满足条件,如果有多行,则每行为根,没有其他条件则
--子节点是自身的子,其他节点也是自身的子。。。循环,因此,connect by level<0也是有结果的,相当于没有写
--connect by level<0是先做递归,先做1次递归,发现level=1,不满足条件,之后结束,并不是丢弃行(和where不同),根总会递归
--但是如果有下属的,不满足条件的,则会丢弃,详细见后面的例子
--connect by rownum,没有其他条件,是直接递归迭代第一行(反复),然后判断rownum条件,不满足条件结束。正是因为
--递归如果没有start with则每行都是根,先第一轮递归,递归到rownum<n不满足后结束,然后其他根肯定不满足,只选出自身一行。
--则剩余其他几行都显示一次,因为第1行递归结束后,继续其他行,发现都不满足,结束。这个rownum不是select里的rownum
--connect by 1=1就不结束了
--没有start with,没有prior...的迭代,不管是level,还是rownum,每行都是根节点,自身或其它节点是子节点
--区别是connect by level会先深度搜索,也就是根---自身---其他节点
--connect by rownum则是不停迭代自身(第一行),然后判断rownum。。。。
---有3行
--它只对第一行做循环,到ROWNUM=4的时候停止。然后另外两条叠加上去,这是因为没有START WITH, 所以第一层所有行都会选中。
如果是先把第一层数据拿出来,再循环,那么结果就不是这样了。
CONNECT BY里面最好用LEVEL控制,ROWNUM的生成顺序不是我们能控制的。
dingjun123@ORADB> SELECT rowid,a,b,level,rownum FROM test1 CONNECT BY rownum<7; --迭代第一行,到第rownum=6结束,其他2行直接显示,select rownum不一样
ROWID A B LEVEL ROWNUM
------------------ ---------- ---------- ---------- ----------
AAAVu6AAEAAAsF2AAA 1 1 1 1 --第1到第6反复递归第一行
AAAVu6AAEAAAsF2AAA 1 1 2 2
AAAVu6AAEAAAsF2AAA 1 1 3 3
AAAVu6AAEAAAsF2AAA 1 1 4 4
AAAVu6AAEAAAsF2AAA 1 1 5 5
AAAVu6AAEAAAsF2AAA 1 1 6 6
AAAVu6AAEAAAsF2AAB 1 1 7 --不满足条件,递归结束
AAAVu6AAEAAAsF2AAC 1 2 1 8 --同上
已选择8行。
已用时间: 00: 00: 00.01
dingjun123@ORADB> SELECT rowid,a,b,level,rownum FROM test1 CONNECT BY rownum<-1; --不满足条件,相当于没有写
ROWID A B LEVEL ROWNUM
------------------ ---------- ---------- ---------- ----------
AAAVu6AAEAAAsF2AAA 1 1 1 1
AAAVu6AAEAAAsF2AAB 1 1 2
AAAVu6AAEAAAsF2AAC 1 2 1 3
已选择3行。
已用时间: 00: 00: 00.01
dingjun123@ORADB> SELECT rowid,a,b,level,rownum FROM test1 CONNECT BY rownum<0; --同上
ROWID A B LEVEL ROWNUM
------------------ ---------- ---------- ---------- ----------
AAAVu6AAEAAAsF2AAA 1 1 1 1
AAAVu6AAEAAAsF2AAB 1 1 2
AAAVu6AAEAAAsF2AAC 1 2 1 3
已选择3行。
已用时间: 00: 00: 00.01
dingjun123@ORADB> SELECT rowid,a,b,level,rownum FROM test1 CONNECT BY 1=0; --同上
ROWID A B LEVEL ROWNUM
------------------ ---------- ---------- ---------- ----------
AAAVu6AAEAAAsF2AAA 1 1 1 1
AAAVu6AAEAAAsF2AAB 1 1 2
AAAVu6AAEAAAsF2AAC 1 2 1 3
已选择3行。
已用时间: 00: 00: 00.01
dingjun123@ORADB> SELECT rowid,a,b,level,rownum FROM test1 CONNECT BY level<0; --同上
ROWID A B LEVEL ROWNUM
------------------ ---------- ---------- ---------- ----------
AAAVu6AAEAAAsF2AAA 1 1 1 1
AAAVu6AAEAAAsF2AAB 1 1 2
AAAVu6AAEAAAsF2AAC 1 2 1 3
已选择3行。
dingjun123@ORADB> SELECT rowid,a,b,level,rownum FROM test1 CONNECT BY level<3; --每行为根迭代,自身和其他行是子节点
ROWID A B LEVEL ROWNUM
------------------ ---------- ---------- ---------- ----------
AAAVu6AAEAAAsF2AAA 1 1 1 1 --根,其他包括自身的3行是子
AAAVu6AAEAAAsF2AAA 1 1 2 2
AAAVu6AAEAAAsF2AAB 1 2 3
AAAVu6AAEAAAsF2AAC 1 2 2 4
AAAVu6AAEAAAsF2AAB 1 1 5
AAAVu6AAEAAAsF2AAA 1 1 2 6
AAAVu6AAEAAAsF2AAB 1 2 7
AAAVu6AAEAAAsF2AAC 1 2 2 8
AAAVu6AAEAAAsF2AAC 1 2 1 9
AAAVu6AAEAAAsF2AAA 1 1 2 10
AAAVu6AAEAAAsF2AAB 1 2 11
AAAVu6AAEAAAsF2AAC 1 2 2 12
已选择12行。
SELECT rowid,a,b,level,rownum FROM test1 CONNECT BY level<4; --3条记录有39行
ROWID A B LEVEL ROWNUM
AAAVu6AAEAAAsF0AAA 1 1 1 1 ----
AAAVu6AAEAAAsF0AAA 1 1 2 2
AAAVu6AAEAAAsF0AAA 1 1 3 3 第一行到第5行是level=2,第1行自身level=1,level=2
AAAVu6AAEAAAsF0AAB 1 3 4 对于level=3的又从自身开始,N条记录
AAAVu6AAEAAAsF0AAC 1 2 3 5 总数目等比数列和a1(1-q^n)/(1-q)=N(1-N^level)/(1-N)
=3(1-3^3)(1-3)
AAAVu6AAEAAAsF0AAB 1 2 6 ----
AAAVu6AAEAAAsF0AAA 1 1 3 7
AAAVu6AAEAAAsF0AAB 1 3 8
AAAVu6AAEAAAsF0AAC 1 2 3 9
AAAVu6AAEAAAsF0AAC 1 2 2 10
AAAVu6AAEAAAsF0AAA 1 1 3 11
AAAVu6AAEAAAsF0AAB 1 3 12
AAAVu6AAEAAAsF0AAC 1 2 3 13
AAAVu6AAEAAAsF0AAB 1 1 14
AAAVu6AAEAAAsF0AAA 1 1 2 15
AAAVu6AAEAAAsF0AAA 1 1 3 16
AAAVu6AAEAAAsF0AAB 1 3 17
AAAVu6AAEAAAsF0AAC 1 2 3 18
AAAVu6AAEAAAsF0AAB 1 2 19
AAAVu6AAEAAAsF0AAA 1 1 3 20
AAAVu6AAEAAAsF0AAB 1 3 21
AAAVu6AAEAAAsF0AAC 1 2 3 22
AAAVu6AAEAAAsF0AAC 1 2 2 23
AAAVu6AAEAAAsF0AAA 1 1 3 24
AAAVu6AAEAAAsF0AAB 1 3 25
AAAVu6AAEAAAsF0AAC 1 2 3 26
AAAVu6AAEAAAsF0AAC 1 2 1 27
AAAVu6AAEAAAsF0AAA 1 1 2 28
AAAVu6AAEAAAsF0AAA 1 1 3 29
AAAVu6AAEAAAsF0AAB 1 3 30
AAAVu6AAEAAAsF0AAC 1 2 3 31
AAAVu6AAEAAAsF0AAB 1 2 32
AAAVu6AAEAAAsF0AAA 1 1 3 33
AAAVu6AAEAAAsF0AAB 1 3 34
AAAVu6AAEAAAsF0AAC 1 2 3 35
AAAVu6AAEAAAsF0AAC 1 2 2 36
AAAVu6AAEAAAsF0AAA 1 1 3 37
AAAVu6AAEAAAsF0AAB 1 3 38
AAAVu6AAEAAAsF0AAC 1 2 3 39
----------------例子---------------
DROP TABLE tt;
CREATE TABLE tt(ID number,NAME VARCHAR2(10));
INSERT INTO tt VALUES(1,'aa');
INSERT INTO tt VALUES(2,'bb');
INSERT INTO tt VALUES(3,'cc');
COMMIT;
加个level就明白了,connect by level递归,无其他条件,就是每行都是根,然后自身和其他行是子孙,反复迭代
SQL> select ID,NAME,LEVEL from tt connect by level < 3;
ID NAME LEVEL
---------- ---------- ----------
1 aa 1 --根
1 aa 2
2 bb 2
3 cc 2 --包括自身的3个子孙,满足level<3条件结束
2 bb 1
1 aa 2
2 bb 2
3 cc 2
3 cc 1
1 aa 2
2 bb 2
3 cc 2
12 rows selected
也就是对于记录数为N的,如果level最大为m,那么相应的层次c上面的记录数是N^c,因此所有的记录数就是N+N^2+N^3+....N^m=N(1-N^m)/(1-m),
比如3条记录数的,当level<4的话,m=3,则总记录数为39条。找个规律就行了,也就是先深度搜索
同样,下面的也是每行为根,不同的是只搜索level<id
注意一点,根总会递归出来的(不会丢弃),但是下属子节点会判断不满足丢弃行,
比如第一行,虽然id=1,不满足level<id,但是也会出现,和下面的类似
select * from dual connect by level <0;返回一行结果
SQL> select ID,NAME,LEVEL from tt connect by LEVEL < ID;
ID NAME LEVEL
---------- ---------- ----------
1 aa 1
3 cc 2 --bb的id=2不满足条件
2 bb 1
3 cc 2
3 cc 1
3 cc 2
6 rows selected
--因为level<=1或level<0都会返回一条数据
select rnum from
(select level rnum
from dual
connect by level <= 2 - 1)
where 2 <> 1
/
竟然返回
RNUM
---------
1
with t as
(select 1 id from dual union all
select 2 from dual)
select id,level from t connect by level<=10
order by id,level;
select 2*(1-power(2,10))/-1 from dual;
q≠1时 Sn=a1(1-q^n)/(1-q)=(a1-anq)/(1-q)
q=1时Sn=na1
select * from all_objects connect by rownum<=10;
在某个啥啥帖子里看到 rownum,也就是 COUNT 这个操作是最后生成的,在where之后
SELECT ROWNUM n2 FROM DUAL where level=4 CONNECT BY ROWNUM<=5
意味着.
先 递归第一次,然后level=1 ,此时该level不满足level=4的条件,因此 rownum是0,依然满足rownum<=5.
然后递归第二次,然后level=2,此时该level不满足level=4的条件,因此 rownum是0,依然满足rownum<=5.
然后递归第三次,然后level=3,此时该level不满足level=4的条件,因此 rownum是0,依然满足rownum<=5.
然后递归第四次,然后level=4,此时该level满足level=4的条件,因此 rownum是1,依然满足rownum<=5.
然后递归第五次,然后level=5,此时该level不满足level=4的条件,因此 rownum是1,依然满足rownum<=5.
.....
然后就是天荒地老..海枯石烂..精尽人亡...内存溢出..
大概是这样
connect by level<=-1也会产生一行,这个要注意
=3不行,必须<=3
SELECT LEVEL,ID,manager_id FROM s_emp
START WITH manager_id IS NULL
CONNECT BY PRIOR ID=manager_id AND LEVEL<=3;
第1条和第2条要理解递归的本质
dingjun123@ORADB> with t as
2 (select 1 id from dual union all select 2 from dual)
3 select level
4 from t
5 connect by level<3
6 ;
LEVEL
----------
1
2
2
1
2
2
已选择6行。
已用时间: 00: 00: 00.01
dingjun123@ORADB> ed
已写入 file afiedt.buf
1 with t as
2 (select 1 id from dual union all select 2 from dual)
3 select level
4 from t
5 connect by level<3
6* and prior dbms_random.value is not null
7 /
LEVEL
----------
1
2
2
1
2
2
已选择6行。
已用时间: 00: 00: 00.03
已用时间: 00: 00: 00.01
--加上id自连接,必须加上dbms_random,这样相当于每行单独递归的次数,不向上面一样了
dingjun123@ORADB> ed
已写入 file afiedt.buf
1 with t as
2 (select 1 id from dual union all select 2 from dual)
3 select level
4 from t
5 connect by level<3
6 and prior id = id
7* and prior dbms_random.value is not null
dingjun123@ORADB> /
LEVEL
----------
1
2
1
2
已选择4行。
已用时间: 00: 00: 00.01
dingjun123@ORADB> ed
已写入 file afiedt.buf
1 with t as
2 (select 1 id from dual union all select 2 from dual)
3 select level
4 from t
5 connect by level<3
6* and prior id = id
dingjun123@ORADB> /
ERROR:
ORA-01436: 用户数据中的 CONNECT BY 循环
未选定行
对于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是一个只有一条记录的表,如果表有多条记录,将会怎样?
下面开始实验
环境:windows xp sp2 + Oracle 9208
(10.1版本connect by有问题)
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;
复制代码展示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楼中所说的,我想你应该就能明白了。
———————————————————————我是Long Long Ago的大坑的分界线———————————————————————————
事实上我们有更好的办法来处理:
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,就会碰到问题,千万要注意。
对于记录数N,则第m层记录数为N^m
N=3,LEVEL<=1 s=N
LEVEL<=2 s=N^1+N^2
LEVEL<=3 s=N^1+N^2+N^3
...
LEVEL<=m s=N^1+N^2+N^3+....N^m
等比数列q=N,a1=N
s=N(1-N^m)/(1-N) 其中m为需要迭代的level最大值
dingjun123@ORADB> select * from t;
ID
----------
1
1
已选择2行。
已用时间: 00: 00: 00.04
dingjun123@ORADB> select rownum from t connect by rownum <= 2;
ROWNUM
----------
1
2
3
已选择3行。
已用时间: 00: 00: 00.01
connect by 的本质分析
执行下面两句:
select level,rownum from dual connect by level<=10;
select level,rownum from dual connect by rownum<=10;
两句显示的效果完全一样,
但是,如果select有2条或更多,效果就大不一样
select A.TABLE_NAME,level,rownum from (select * from USER_TABLES A WHERE ROWNUM<=2 ) A connect by level<=10; --有2046条
select A.TABLE_NAME, level,rownum from (select * from USER_TABLES WHERE ROWNUM<=2) A connect by rownum<=10 ; --有11条;
所以,想咨询专家 connect by level 和 connect by rownum 的本质区别;
列个关系列表,也许可以通过数学归纳法,得出其中规律
select 的记录数(m) connect by 层数(n) by level 的记录数 by rownum的记录数
1 10 10 10
2 10 2046 11
3 10 88572 12
4 10 1398100 13
by rownum的记录数 规律很明显: connect by 层数(n) +select 的记录数(m) -1;
by level 的记录数 的规律还没找出
--深刻理解connect by的原理,理解statr with,connect by,理解层次如何生成的
--理解connect by level和connect by rownum的区别,比如掌握level如何生成,rownum如何生成
--connect by level是先做递归,然后判断level是否满足条件,如果有多行,则每行为根,没有其他条件则
--子节点是自身的子,其他节点也是自身的子。。。循环,因此,connect by level<0也是有结果的,相当于没有写
--connect by level<0是先做递归,先做1次递归,发现level=1,不满足条件,之后结束,并不是丢弃行(和where不同),根总会递归
--但是如果有下属的,不满足条件的,则会丢弃,详细见后面的例子
--connect by rownum,没有其他条件,是直接递归迭代第一行(反复),然后判断rownum条件,不满足条件结束。正是因为
--递归如果没有start with则每行都是根,先第一轮递归,递归到rownum<n不满足后结束,然后其他根肯定不满足,只选出自身一行。
--则剩余其他几行都显示一次,因为第1行递归结束后,继续其他行,发现都不满足,结束。这个rownum不是select里的rownum
--connect by 1=1就不结束了
--没有start with,没有prior...的迭代,不管是level,还是rownum,每行都是根节点,自身或其它节点是子节点
--区别是connect by level会先深度搜索,也就是根---自身---其他节点
--connect by rownum则是不停迭代自身(第一行),然后判断rownum。。。。
---有3行
--它只对第一行做循环,到ROWNUM=4的时候停止。然后另外两条叠加上去,这是因为没有START WITH, 所以第一层所有行都会选中。
如果是先把第一层数据拿出来,再循环,那么结果就不是这样了。
CONNECT BY里面最好用LEVEL控制,ROWNUM的生成顺序不是我们能控制的。
dingjun123@ORADB> SELECT rowid,a,b,level,rownum FROM test1 CONNECT BY rownum<7; --迭代第一行,到第rownum=6结束,其他2行直接显示,select rownum不一样
ROWID A B LEVEL ROWNUM
------------------ ---------- ---------- ---------- ----------
AAAVu6AAEAAAsF2AAA 1 1 1 1 --第1到第6反复递归第一行
AAAVu6AAEAAAsF2AAA 1 1 2 2
AAAVu6AAEAAAsF2AAA 1 1 3 3
AAAVu6AAEAAAsF2AAA 1 1 4 4
AAAVu6AAEAAAsF2AAA 1 1 5 5
AAAVu6AAEAAAsF2AAA 1 1 6 6
AAAVu6AAEAAAsF2AAB 1 1 7 --不满足条件,递归结束
AAAVu6AAEAAAsF2AAC 1 2 1 8 --同上
已选择8行。
已用时间: 00: 00: 00.01
dingjun123@ORADB> SELECT rowid,a,b,level,rownum FROM test1 CONNECT BY rownum<-1; --不满足条件,相当于没有写
ROWID A B LEVEL ROWNUM
------------------ ---------- ---------- ---------- ----------
AAAVu6AAEAAAsF2AAA 1 1 1 1
AAAVu6AAEAAAsF2AAB 1 1 2
AAAVu6AAEAAAsF2AAC 1 2 1 3
已选择3行。
已用时间: 00: 00: 00.01
dingjun123@ORADB> SELECT rowid,a,b,level,rownum FROM test1 CONNECT BY rownum<0; --同上
ROWID A B LEVEL ROWNUM
------------------ ---------- ---------- ---------- ----------
AAAVu6AAEAAAsF2AAA 1 1 1 1
AAAVu6AAEAAAsF2AAB 1 1 2
AAAVu6AAEAAAsF2AAC 1 2 1 3
已选择3行。
已用时间: 00: 00: 00.01
dingjun123@ORADB> SELECT rowid,a,b,level,rownum FROM test1 CONNECT BY 1=0; --同上
ROWID A B LEVEL ROWNUM
------------------ ---------- ---------- ---------- ----------
AAAVu6AAEAAAsF2AAA 1 1 1 1
AAAVu6AAEAAAsF2AAB 1 1 2
AAAVu6AAEAAAsF2AAC 1 2 1 3
已选择3行。
已用时间: 00: 00: 00.01
dingjun123@ORADB> SELECT rowid,a,b,level,rownum FROM test1 CONNECT BY level<0; --同上
ROWID A B LEVEL ROWNUM
------------------ ---------- ---------- ---------- ----------
AAAVu6AAEAAAsF2AAA 1 1 1 1
AAAVu6AAEAAAsF2AAB 1 1 2
AAAVu6AAEAAAsF2AAC 1 2 1 3
已选择3行。
dingjun123@ORADB> SELECT rowid,a,b,level,rownum FROM test1 CONNECT BY level<3; --每行为根迭代,自身和其他行是子节点
ROWID A B LEVEL ROWNUM
------------------ ---------- ---------- ---------- ----------
AAAVu6AAEAAAsF2AAA 1 1 1 1 --根,其他包括自身的3行是子
AAAVu6AAEAAAsF2AAA 1 1 2 2
AAAVu6AAEAAAsF2AAB 1 2 3
AAAVu6AAEAAAsF2AAC 1 2 2 4
AAAVu6AAEAAAsF2AAB 1 1 5
AAAVu6AAEAAAsF2AAA 1 1 2 6
AAAVu6AAEAAAsF2AAB 1 2 7
AAAVu6AAEAAAsF2AAC 1 2 2 8
AAAVu6AAEAAAsF2AAC 1 2 1 9
AAAVu6AAEAAAsF2AAA 1 1 2 10
AAAVu6AAEAAAsF2AAB 1 2 11
AAAVu6AAEAAAsF2AAC 1 2 2 12
已选择12行。
SELECT rowid,a,b,level,rownum FROM test1 CONNECT BY level<4; --3条记录有39行
ROWID A B LEVEL ROWNUM
AAAVu6AAEAAAsF0AAA 1 1 1 1 ----
AAAVu6AAEAAAsF0AAA 1 1 2 2
AAAVu6AAEAAAsF0AAA 1 1 3 3 第一行到第5行是level=2,第1行自身level=1,level=2
AAAVu6AAEAAAsF0AAB 1 3 4 对于level=3的又从自身开始,N条记录
AAAVu6AAEAAAsF0AAC 1 2 3 5 总数目等比数列和a1(1-q^n)/(1-q)=N(1-N^level)/(1-N)
=3(1-3^3)(1-3)
AAAVu6AAEAAAsF0AAB 1 2 6 ----
AAAVu6AAEAAAsF0AAA 1 1 3 7
AAAVu6AAEAAAsF0AAB 1 3 8
AAAVu6AAEAAAsF0AAC 1 2 3 9
AAAVu6AAEAAAsF0AAC 1 2 2 10
AAAVu6AAEAAAsF0AAA 1 1 3 11
AAAVu6AAEAAAsF0AAB 1 3 12
AAAVu6AAEAAAsF0AAC 1 2 3 13
AAAVu6AAEAAAsF0AAB 1 1 14
AAAVu6AAEAAAsF0AAA 1 1 2 15
AAAVu6AAEAAAsF0AAA 1 1 3 16
AAAVu6AAEAAAsF0AAB 1 3 17
AAAVu6AAEAAAsF0AAC 1 2 3 18
AAAVu6AAEAAAsF0AAB 1 2 19
AAAVu6AAEAAAsF0AAA 1 1 3 20
AAAVu6AAEAAAsF0AAB 1 3 21
AAAVu6AAEAAAsF0AAC 1 2 3 22
AAAVu6AAEAAAsF0AAC 1 2 2 23
AAAVu6AAEAAAsF0AAA 1 1 3 24
AAAVu6AAEAAAsF0AAB 1 3 25
AAAVu6AAEAAAsF0AAC 1 2 3 26
AAAVu6AAEAAAsF0AAC 1 2 1 27
AAAVu6AAEAAAsF0AAA 1 1 2 28
AAAVu6AAEAAAsF0AAA 1 1 3 29
AAAVu6AAEAAAsF0AAB 1 3 30
AAAVu6AAEAAAsF0AAC 1 2 3 31
AAAVu6AAEAAAsF0AAB 1 2 32
AAAVu6AAEAAAsF0AAA 1 1 3 33
AAAVu6AAEAAAsF0AAB 1 3 34
AAAVu6AAEAAAsF0AAC 1 2 3 35
AAAVu6AAEAAAsF0AAC 1 2 2 36
AAAVu6AAEAAAsF0AAA 1 1 3 37
AAAVu6AAEAAAsF0AAB 1 3 38
AAAVu6AAEAAAsF0AAC 1 2 3 39
----------------例子---------------
DROP TABLE tt;
CREATE TABLE tt(ID number,NAME VARCHAR2(10));
INSERT INTO tt VALUES(1,'aa');
INSERT INTO tt VALUES(2,'bb');
INSERT INTO tt VALUES(3,'cc');
COMMIT;
加个level就明白了,connect by level递归,无其他条件,就是每行都是根,然后自身和其他行是子孙,反复迭代
SQL> select ID,NAME,LEVEL from tt connect by level < 3;
ID NAME LEVEL
---------- ---------- ----------
1 aa 1 --根
1 aa 2
2 bb 2
3 cc 2 --包括自身的3个子孙,满足level<3条件结束
2 bb 1
1 aa 2
2 bb 2
3 cc 2
3 cc 1
1 aa 2
2 bb 2
3 cc 2
12 rows selected
也就是对于记录数为N的,如果level最大为m,那么相应的层次c上面的记录数是N^c,因此所有的记录数就是N+N^2+N^3+....N^m=N(1-N^m)/(1-m),
比如3条记录数的,当level<4的话,m=3,则总记录数为39条。找个规律就行了,也就是先深度搜索
同样,下面的也是每行为根,不同的是只搜索level<id
注意一点,根总会递归出来的(不会丢弃),但是下属子节点会判断不满足丢弃行,
比如第一行,虽然id=1,不满足level<id,但是也会出现,和下面的类似
select * from dual connect by level <0;返回一行结果
SQL> select ID,NAME,LEVEL from tt connect by LEVEL < ID;
ID NAME LEVEL
---------- ---------- ----------
1 aa 1
3 cc 2 --bb的id=2不满足条件
2 bb 1
3 cc 2
3 cc 1
3 cc 2
6 rows selected
--因为level<=1或level<0都会返回一条数据
select rnum from
(select level rnum
from dual
connect by level <= 2 - 1)
where 2 <> 1
/
竟然返回
RNUM
---------
1
with t as
(select 1 id from dual union all
select 2 from dual)
select id,level from t connect by level<=10
order by id,level;
select 2*(1-power(2,10))/-1 from dual;
q≠1时 Sn=a1(1-q^n)/(1-q)=(a1-anq)/(1-q)
q=1时Sn=na1
select * from all_objects connect by rownum<=10;
在某个啥啥帖子里看到 rownum,也就是 COUNT 这个操作是最后生成的,在where之后
SELECT ROWNUM n2 FROM DUAL where level=4 CONNECT BY ROWNUM<=5
意味着.
先 递归第一次,然后level=1 ,此时该level不满足level=4的条件,因此 rownum是0,依然满足rownum<=5.
然后递归第二次,然后level=2,此时该level不满足level=4的条件,因此 rownum是0,依然满足rownum<=5.
然后递归第三次,然后level=3,此时该level不满足level=4的条件,因此 rownum是0,依然满足rownum<=5.
然后递归第四次,然后level=4,此时该level满足level=4的条件,因此 rownum是1,依然满足rownum<=5.
然后递归第五次,然后level=5,此时该level不满足level=4的条件,因此 rownum是1,依然满足rownum<=5.
.....
然后就是天荒地老..海枯石烂..精尽人亡...内存溢出..
大概是这样
connect by level<=-1也会产生一行,这个要注意
=3不行,必须<=3
SELECT LEVEL,ID,manager_id FROM s_emp
START WITH manager_id IS NULL
CONNECT BY PRIOR ID=manager_id AND LEVEL<=3;
第1条和第2条要理解递归的本质
dingjun123@ORADB> with t as
2 (select 1 id from dual union all select 2 from dual)
3 select level
4 from t
5 connect by level<3
6 ;
LEVEL
----------
1
2
2
1
2
2
已选择6行。
已用时间: 00: 00: 00.01
dingjun123@ORADB> ed
已写入 file afiedt.buf
1 with t as
2 (select 1 id from dual union all select 2 from dual)
3 select level
4 from t
5 connect by level<3
6* and prior dbms_random.value is not null
7 /
LEVEL
----------
1
2
2
1
2
2
已选择6行。
已用时间: 00: 00: 00.03
已用时间: 00: 00: 00.01
--加上id自连接,必须加上dbms_random,这样相当于每行单独递归的次数,不向上面一样了
dingjun123@ORADB> ed
已写入 file afiedt.buf
1 with t as
2 (select 1 id from dual union all select 2 from dual)
3 select level
4 from t
5 connect by level<3
6 and prior id = id
7* and prior dbms_random.value is not null
dingjun123@ORADB> /
LEVEL
----------
1
2
1
2
已选择4行。
已用时间: 00: 00: 00.01
dingjun123@ORADB> ed
已写入 file afiedt.buf
1 with t as
2 (select 1 id from dual union all select 2 from dual)
3 select level
4 from t
5 connect by level<3
6* and prior id = id
dingjun123@ORADB> /
ERROR:
ORA-01436: 用户数据中的 CONNECT BY 循环
未选定行
对于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是一个只有一条记录的表,如果表有多条记录,将会怎样?
下面开始实验
环境:windows xp sp2 + Oracle 9208
(10.1版本connect by有问题)
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;
复制代码展示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楼中所说的,我想你应该就能明白了。
———————————————————————我是Long Long Ago的大坑的分界线———————————————————————————
事实上我们有更好的办法来处理:
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,就会碰到问题,千万要注意。
SQL> with tmp as (select 2 a from dual union all select 3 from dual union all select 4 from dual)
2 select rownum, b.*
3 from (select a.a, sum(a.a) over(order by rownum) - rownum + 1 psum
4 from tmp a) b
5 connect by rownum <= b.psum;
ROWNUM A PSUM
---------- ---------- ----------
1 2 2
2 2 2
3 3 4
4 3 4
5 4 7
6 4 7
7 4 7
8 3 4
9 4 7
9 rows selected
以上红色部分,实在搞不懂为什么会出现在结果集中。
因为按connect by rownum <= psum的条件,8、9都是大于4、7的。但是却出现在了结果集中,不明白这是何原因。
有谁可以解释一下?
您只给出了内层的查询,我不明白这是什么意思......
我能明白这个内层查询的含义,但是不能理解外层查询中rownum=8/9的情况下,为何会出现psum=4/7的情况。
因为此时rownum(8/9) > psum(4/7)了,为何会在connect by rownum <= psum的条件下出现这样的结果?
虽然结果是我想要的,但是不明白这是为什么。
实际上,我是想知道,为何数据会是这样展现的?他的过程是怎么样的?
对于结果:
a b
2 2
3 4
4 7
可以推算,
a=2时,rownum <= 2(b的值),此时rownum=1,则有:
rownum a b
1 2 2
2 2 2--直到rownum=2
a=3时,rownum <= 4,此时rownum=3,则有:
rownum a b
3 3 4
4 3 4--直到rownum=4
a=3时,rownum <= 7,此时rownum=5,则有:
rownum a b
5 4 7
6 4 7
7 4 7--直到rownum=7
于是经过connect by rownum <= psum就可以得到:
1 2 2
2 2 2
3 3 4
4 3 4
5 4 7
6 4 7
7 4 7
8 3 4
9 4 7
但是接下来红色部分的8、9是如何推算的?
rownum a b
8 3 4
9 4 7
还是我这样推算是错误的?
原帖由 CaptainKobe 于 2009-12-15 16:32 发表
SQL> SELECT ROWNUM FROM DUAL CONNECT BY ROWNUM
你这个是静态的,而且是单条的情况下。
考虑多条,多个rownum限定值时,情况就没有那么简单了。
至于你的rownum<=10为什么有11条,我就不得而知了。应该是10条:
SQL> select rownum from dual connect by rownum <= 10 ;
ROWNUM
----------
1
2
3
4
5
6
7
8
9
10
10 rows selected
总结了下规律,发现
不管rownum如何限制,他首先会根据指定的psum值生成若干条数据,直到rownum=这个指定的值时停下,然后转入下一个psum。如rownum=3,而psum=4时,会生成rownum=3和4两条记录。
因此生成的数据为psum-开始时的rownum+1,比如上面的4-3+1=2。
但是,oracle在最后还会根据每个psum自动生成一行,也就是将原始表再复制一次(第一条不复制,不管psum是否有重复都会复制)。
于是生成的记录变成了:4-3+1+1=3了。就是我们所要的行数。
加上LEVEL就明白了:
with tmp as (select 2 a from dual union all select 3 from dual union all select 4 from dual)
select rownum,level, b.*
from (select a.a, sum(a.a) over(order by rownum) - rownum + 1 psum
from tmp a) b
connect by rownum <= b.psum;
ROWNUM LEVEL A PSUM
---------- ---------- ---------- ----------
1 1 2 2
2 2 2 2
3 3 3 4
4 4 3 4
5 5 4 7
6 6 4 7
7 7 4 7
8 1 3 4
9 1 4 7
LEVEL 1是不受CONNECT BY条件限制的。
因为你没有指定START WITH, 所以三行全部都是起点,即结果中你看到的三个LEVEL 1的行。这三行是一定会出来的,不受你CONNECT BY限制。
从2,2起点的结果从LEVEL 1一直到LEVEL 7
其他两行的结果就是你看到的8, 9行,它们没有更高的LEVEL因为从LEVEL 2开始已经不满足CONNECT BY条件,遍历就终止了。
我大概看明白你的意思了。
2 2
3 4
4 7
是不是可以这样理解,我开始查询的时候,rownum=1。然后由于connect by rownum <= 2,于是生成两条记录。
即:
rownum a b
1 2 2
2 2 2
然后,此时rownum=2,rownum再与4比较,发现比4小。于是再生成记录,直到=4为止,即:
rownum a b
1 2 2
2 2 2
3 3 4
4 3 4
然后,此时rownum=4,再与7比较,发现比7小。于是再生成记录,直到=7为止,即:
rownum a b
1 2 2
2 2 2
3 3 4
4 3 4
5 4 7
6 4 7
7 4 7
最后发现第一轮已经轮询完了,然后转入第二轮,由于没有指定start with,
所以接下来的数据都只生成一条,其他的rownum条件都已经不满足rownum<=psum的条件了
理解正确。
CONNECT BY一般是要写前后关系的,即 PRIOR 列名1 = 列名2
没有这个关系的用法经常是在表中只有一行的情况,(比如DUEL),然后用ROWNUM或LEVEL来控制输出的行数。
2 select rownum, b.*
3 from (select a.a, sum(a.a) over(order by rownum) - rownum + 1 psum
4 from tmp a) b
5 connect by rownum <= b.psum;
ROWNUM A PSUM
---------- ---------- ----------
1 2 2
2 2 2
3 3 4
4 3 4
5 4 7
6 4 7
7 4 7
8 3 4
9 4 7
9 rows selected
以上红色部分,实在搞不懂为什么会出现在结果集中。
因为按connect by rownum <= psum的条件,8、9都是大于4、7的。但是却出现在了结果集中,不明白这是何原因。
有谁可以解释一下?
您只给出了内层的查询,我不明白这是什么意思......
我能明白这个内层查询的含义,但是不能理解外层查询中rownum=8/9的情况下,为何会出现psum=4/7的情况。
因为此时rownum(8/9) > psum(4/7)了,为何会在connect by rownum <= psum的条件下出现这样的结果?
虽然结果是我想要的,但是不明白这是为什么。
实际上,我是想知道,为何数据会是这样展现的?他的过程是怎么样的?
对于结果:
a b
2 2
3 4
4 7
可以推算,
a=2时,rownum <= 2(b的值),此时rownum=1,则有:
rownum a b
1 2 2
2 2 2--直到rownum=2
a=3时,rownum <= 4,此时rownum=3,则有:
rownum a b
3 3 4
4 3 4--直到rownum=4
a=3时,rownum <= 7,此时rownum=5,则有:
rownum a b
5 4 7
6 4 7
7 4 7--直到rownum=7
于是经过connect by rownum <= psum就可以得到:
1 2 2
2 2 2
3 3 4
4 3 4
5 4 7
6 4 7
7 4 7
8 3 4
9 4 7
但是接下来红色部分的8、9是如何推算的?
rownum a b
8 3 4
9 4 7
还是我这样推算是错误的?
原帖由 CaptainKobe 于 2009-12-15 16:32 发表
SQL> SELECT ROWNUM FROM DUAL CONNECT BY ROWNUM
你这个是静态的,而且是单条的情况下。
考虑多条,多个rownum限定值时,情况就没有那么简单了。
至于你的rownum<=10为什么有11条,我就不得而知了。应该是10条:
SQL> select rownum from dual connect by rownum <= 10 ;
ROWNUM
----------
1
2
3
4
5
6
7
8
9
10
10 rows selected
总结了下规律,发现
不管rownum如何限制,他首先会根据指定的psum值生成若干条数据,直到rownum=这个指定的值时停下,然后转入下一个psum。如rownum=3,而psum=4时,会生成rownum=3和4两条记录。
因此生成的数据为psum-开始时的rownum+1,比如上面的4-3+1=2。
但是,oracle在最后还会根据每个psum自动生成一行,也就是将原始表再复制一次(第一条不复制,不管psum是否有重复都会复制)。
于是生成的记录变成了:4-3+1+1=3了。就是我们所要的行数。
加上LEVEL就明白了:
with tmp as (select 2 a from dual union all select 3 from dual union all select 4 from dual)
select rownum,level, b.*
from (select a.a, sum(a.a) over(order by rownum) - rownum + 1 psum
from tmp a) b
connect by rownum <= b.psum;
ROWNUM LEVEL A PSUM
---------- ---------- ---------- ----------
1 1 2 2
2 2 2 2
3 3 3 4
4 4 3 4
5 5 4 7
6 6 4 7
7 7 4 7
8 1 3 4
9 1 4 7
LEVEL 1是不受CONNECT BY条件限制的。
因为你没有指定START WITH, 所以三行全部都是起点,即结果中你看到的三个LEVEL 1的行。这三行是一定会出来的,不受你CONNECT BY限制。
从2,2起点的结果从LEVEL 1一直到LEVEL 7
其他两行的结果就是你看到的8, 9行,它们没有更高的LEVEL因为从LEVEL 2开始已经不满足CONNECT BY条件,遍历就终止了。
我大概看明白你的意思了。
2 2
3 4
4 7
是不是可以这样理解,我开始查询的时候,rownum=1。然后由于connect by rownum <= 2,于是生成两条记录。
即:
rownum a b
1 2 2
2 2 2
然后,此时rownum=2,rownum再与4比较,发现比4小。于是再生成记录,直到=4为止,即:
rownum a b
1 2 2
2 2 2
3 3 4
4 3 4
然后,此时rownum=4,再与7比较,发现比7小。于是再生成记录,直到=7为止,即:
rownum a b
1 2 2
2 2 2
3 3 4
4 3 4
5 4 7
6 4 7
7 4 7
最后发现第一轮已经轮询完了,然后转入第二轮,由于没有指定start with,
所以接下来的数据都只生成一条,其他的rownum条件都已经不满足rownum<=psum的条件了
理解正确。
CONNECT BY一般是要写前后关系的,即 PRIOR 列名1 = 列名2
没有这个关系的用法经常是在表中只有一行的情况,(比如DUEL),然后用ROWNUM或LEVEL来控制输出的行数。
0 0
- connect by rownum及connect by level的内部执行原理及过程
- level、connect by、rownum使用
- 使用connect by level/rownum实现连续数字的插入
- 使用connect by level/rownum实现连续数字的插入
- 【CONNECT BY】使用connect by level/rownum实现连续数字的插入
- connect by rownum造表
- Oracle数据库的CONNECT BY ROWNUM研究
- CONNECT BY LEVEL
- Oracle connect by level
- level和 connect by 的结合使用
- connect by level语法的理解
- oracle connect by level 的用法
- connect by level 的小应用
- 行转列 SQL ,connect by level
- oracle connect by level 应用
- oracle connect by level 应用
- row_number(partition by..)以及connect by level的使用
- oracle rownum和connect by 扫盲
- quartz GUI
- Grep命令详解
- jdk环境变量配置及配置原因
- ViewPager切换滑动速度修改
- 位运算符之异或的化腐朽为神奇
- connect by rownum及connect by level的内部执行原理及过程
- 软工文档——可行性研究报告
- UITableView 数据展示 cell
- 如何判断Android手机当前是否联网
- 顺丰嘿客:看上去很美的O2O乌托邦
- ORACLE 内置函数之 GREATEST 和 LEAST(求多列的最大值,最小值)
- C++基础学习教程(三)
- 使用 Tkprof 分析 ORACLE 跟踪文件
- 【剑指offer】面试题7:用两个栈实现队列