Sql 为什么表上的CONNECT BY LEVEL返回额外的行?
在表上执行CONNECT BY LEVEL时,使用CONNECT BY似乎返回了太多的行。发生的事情背后的逻辑是什么 假设下表:Sql 为什么表上的CONNECT BY LEVEL返回额外的行?,sql,oracle,connect-by,Sql,Oracle,Connect By,在表上执行CONNECT BY LEVEL时,使用CONNECT BY似乎返回了太多的行。发生的事情背后的逻辑是什么 假设下表: create table a ( id number ); insert into a values (1); insert into a values (2); insert into a values (3); 此查询返回12行 表A中的每一行LVL列的值为1,表A中的每一行LVL列的值为3,其中LVL列为2,即: ID | LVL ---+----- 1
create table a ( id number );
insert into a values (1);
insert into a values (2);
insert into a values (3);
此查询返回12行
表A中的每一行LVL列的值为1,表A中的每一行LVL列的值为3,其中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行,或者为什么对于ID列的每个值,有三行LVL为2,只有一行LVL为1
为ID.1的每个值增加连接到3的级别数,其中LVL为1、3(其中LVL为2)和9(其中LVL为3)。这似乎表明返回的行数是表A中的行数乘以LVL减1的幂
我认为这些查询将与下面相同,返回
6排
对我来说,在解释应该发生的事情时,问题并不是特别清楚。这些功能发生了什么?为什么前两个查询与第三个查询不一样?在将最终查询与其他查询进行比较时,您正在将苹果与桔子进行比较,因为该级别与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行。然后将其按比例分配到原始的3行,输出6行。在第一个查询中,您只需按级别进行连接。 所以,如果使用级别的connect by时未使用start with子句和PREVIOR运算符,则对将子行连接到父行没有任何限制。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
您可以使用以下技巧来解决此问题:
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
sys_connect_by_path在MySQL5中是否有类似的东西?
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
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