为什么CONNECT BY在表级别返回多余的行?(Why does CONNECT BY LEVEL

2019-07-04 02:00发布

使用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

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

Answer 1:

在第一个查询,您仅由水平连接。 所以,如果水平<= 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的记录。



Answer 2:

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


Answer 3:

你比较其他最终的查询时,水平在隔离到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行作为输出。



Answer 4:

您可以使用下面的技术来解决这个问题:

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


文章来源: Why does CONNECT BY LEVEL on a table return extra rows?