使用CONNECT BY LEVEL似乎在桌子上,就对返回太多行。 这背后发生了什么逻辑?
假设如下表:
create table a ( id number );
insert into a values (1);
insert into a values (2);
insert into a values (3);
该查询返回12行( SQL小提琴 )。
select id, level as lvl
from a
connect by level <= 2
order by id, level
对于每个表A与柱LVL在表A是1和三个每个其中列LVL为2,即,值一个行:
ID | LVL
---+-----
1 | 1
1 | 2
1 | 2
1 | 2
2 | 1
2 | 2
2 | 2
2 | 2
3 | 1
3 | 2
3 | 2
3 | 2
它相当于此查询,返回相同的结果。
select id, level as lvl
from dual
cross join a
connect by level <= 2
order by id, level
我不明白为什么这些查询返回12行,或者为什么有三排,其中LVL是2,只有一个地方LVL为1的ID列的每个值。
增加在“连接”到3个的数目返回13行对ID的每个值。 1其中LVL为1,3,其中LVL为2和9中,其中LVL为3。这似乎表明,返回的行是行的表A中的数量,以LVL的值的幂减1。
我不得不说,虽然这些查询是一样的;下面,返回6行
select id, lvl
from ( select level as lvl
from dual
connect by level <= 2
)
cross join a
order by id, lvl
该文档是不是特别清楚,对我来说,在解释应该发生什么。 发生什么事了这些权力,为什么没有前两个查询与第三?
在第一个查询,您仅由水平连接。 所以,如果水平<= 1,你会得到每个记录1次。 如果电平<= 2,则每级1的时间(1级)得到+ N次(其中N是记录在表中的数量)。 这就像你是交叉的加盟,因为你刚刚采摘的所有记录从表中,直到达到的水平,而无需其他条件限制的结果。 对于水平<= 3,这是再次对每个那些结果的完成。
因此,对于3条记录:
- LVL 1:3记录(所有具有水平1)
- LVL 2:具有水平上具有级别3点的记录1 + 3 * 3记录2 = 12
- LVL 3:3 + 3 * 3 + 3 * 3 * 3 = 39(实际上,每13个记录)。
- LVL 4:开始看到一种模式? :)
它不是一个真正的交叉连接。 交叉连接只会返回那些在此查询结果有2级记录,而与此相连的,你有1级的记录以及具有2级的记录,从而导致3 + 3 * 3,而不是只3 * 3的记录。
当connect by
是不使用start with
子句和prior
运营商,对加盟孩子排到父行没有限制。 而Oracle如何在这种情况下,它由一排连接到更高层次的每一行返回所有可能的排列层次。
SQL> select b
2 , level as lvl
3 , sys_connect_by_path(b, '->') as ph
4 from a
5 connect by level <= 2
6 ;
B LVL PH
---------- ----------
1 1 ->1
1 2 ->1->1
2 2 ->1->2
3 2 ->1->3
2 1 ->2
1 2 ->2->1
2 2 ->2->2
3 2 ->2->3
3 1 ->3
1 2 ->3->1
2 2 ->3->2
3 2 ->3->3
12 rows selected
你比较其他最终的查询时,水平在隔离到1行双表相比较苹果和橘子。
让我们考虑这个查询:
select id, level as lvl
from a
connect by level <= 2
order by id, level
那是什么在说,先从表集(SELECT * FROM A)。 然后,返回的每个行此行连接到前行。 如还没有定义的联接在连接通过,这是有效的笛卡尔加入,所以当你有3行的(1,2,3)1加入到2,1-> 3,2-> 1,2 - > 3,3-> 1和3-> 2并且它们也加入到自己1-> 1,2-> 2和3-> 3。 这些连接是级别= 2。 所以我们有9联接在那里,这就是为什么你会得到12行(3原有的“等级1”行加笛卡尔集)。
所以输出行的数量=行数+(行数^ 2)
在最后一个查询要隔离级别这一
select level as lvl
from dual
connect by level <= 2
这当然返回2行。 然后这被cartesianed到原来的3行,使6行作为输出。
您可以使用下面的技术来解决这个问题:
select id, level as lvl
from a
left outer join (select level l from dual connect by level <= 2) lev on 1 = 1
order by id