为什么表上的CONNECT BY LEVEL会返回额外的行?

Ben*_*Ben 14 sql oracle connect-by

在表上执行时,使用CONNECT BY LEVEL似乎返回太多行.发生了什么事情背后的逻辑是什么?

假设如下表:

create table a ( id number );

insert into a values (1);
insert into a values (2);
insert into a values (3);
Run Code Online (Sandbox Code Playgroud)

此查询返回12行(SQL Fiddle).

 select id, level as lvl
   from a
connect by level <= 2
  order by id, level
Run Code Online (Sandbox Code Playgroud)

表A中每行一行,列LVL的值为1,表LV中的每一行为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
Run Code Online (Sandbox Code Playgroud)

我不明白为什么这些查询会返回12行,或者为什么有三行LVL为2,而对于ID列的每个值,只有一行LVL为1.

增加"连接"到3的级别数会为每个ID值返回13行.1其中LVL是1,其中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
Run Code Online (Sandbox Code Playgroud)

文档是不是特别清楚,对我来说,在解释应该发生什么.这些权力发生了什么,为什么前两个查询不同于第三个?

Gol*_*rol 14

在第一个查询中,只按级别连接.因此,如果level <= 1,您将获得每个记录1次.如果level <= 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记录.


Nic*_*nov 14

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
Run Code Online (Sandbox Code Playgroud)

  • `sys_connect_by_path()`< - 这个关键字解释了一切.这个问题的最佳答案之一(不仅仅是本主题). (3认同)