【问题标题】:Why does CONNECT BY LEVEL on a table return extra rows?为什么表上的 CONNECT BY LEVEL 会返回额外的行?
【发布时间】:2012-11-24 11:15: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 Fiddle)。

 select id, level as lvl
   from a
connect by level <= 2
  order by id, level

表A中每一行,LVL列的值为1,表A中每一列LVL为2,即:

身份证 |层积层 --+----- 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 的行有 3 行,而 LVL 为 1 的行只有 1 行。

对于每个 ID 值,将“连接”的级别数增加到 3 个returns 13 rows。 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

documentation 在解释应该发生的情况时对我来说并不是特别清楚。这些权力发生了什么?为什么前两个查询与第三个查询不同?

【问题讨论】:

  • 我们在 MySQL 5 中是否有类似的东西?

标签: sql oracle connect-by


【解决方案1】:

在第一个查询中,您仅按级别进行连接。 因此,如果 level

所以对于 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 记录。

【讨论】:

    【解决方案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
    

    【讨论】:

    • sys_connect_by_path()
    【解决方案3】:

    在将最终查询与其他查询进行比较时,您将苹果与橙子进行比较,因为 LEVEL 与 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。这些连接是 level=2。所以我们在那里有 9 个连接,这就是为什么你得到 12 行(3 个原始“1 级”行加上笛卡尔集)。

    所以输出的行数 = rowcount + (rowcount^2)

    在最后一个查询中,您将级别隔离到此

    select level  as lvl
               from dual
            connect by level  <= 2
    

    当然返回 2 行。然后将其笛卡尔化到原来的 3 行,输出 6 行。

    【讨论】:

      【解决方案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
      

      【讨论】:

        猜你喜欢
        • 2022-07-06
        • 1970-01-01
        • 1970-01-01
        • 2020-08-01
        • 1970-01-01
        • 1970-01-01
        • 2016-12-11
        • 2012-10-26
        • 1970-01-01
        相关资源
        最近更新 更多