【问题标题】:Oracle Connect By seems to produce too many rowsOracle Connect By 似乎产生了太多行
【发布时间】:2017-01-11 00:09:19
【问题描述】:

Oracle Database 12c 企业版 12.1.0.2.0 版

我希望我只是遗漏了一些东西,但如果我在没有“连接方式”的情况下运行此查询,我会得到 2 行。当我添加“按级别

谁能帮我理解这里发生了什么?我不是在寻找只将每一行重复 4 次的解决方案——我已经得到了。我只是想了解发生了什么以及为什么。

with alpha as (
        select 1 as id
            from dual
    ),
    beta as (
        select 1 as alpha_id,
                1 as beta_no
            from dual
        union all
        select 1 as alpha_id,
                2 as beta_no
            from dual
    )
select a.id,
        b.beta_no,
        level as the_level
    from alpha a
        inner join beta b
            on b.alpha_id = a.id
    connect by level <= 4
    order by a.id,
        b.beta_no,
        level
;
    ID    BETA_NO  THE_LEVEL

     1          1          1
     1          1          2
     1          1          2
     1          1          3
     1          1          3
     1          1          3
     1          1          3
     1          1          4
     1          1          4
     1          1          4
     1          1          4
     1          1          4
     1          1          4
     1          1          4
     1          1          4
     1          2          1
     1          2          2
     1          2          2
     1          2          3
     1          2          3
     1          2          3
     1          2          3
     1          2          4
     1          2          4
     1          2          4
     1          2          4
     1          2          4
     1          2          4
     1          2          4
     1          2          4

已选择 30 行

非常感谢 mathguy。他在下面的答案中提供的第二个链接正是我想要的。具体来说:

  1  with t as (select 1 as id from dual union all
  2             select 2 from dual)
  3  --
  4  select id, level
  5        ,prior id
  6        ,sys_connect_by_path(id,'=>') as cpath
  7  from   t
  8* connect by level <= 3
SQL> /

        ID      LEVEL    PRIORID CPATH
---------- ---------- ---------- --------------------------------------------------
         1          1            =>1
         1          2          1 =>1=>1
         1          3          1 =>1=>1=>1
         2          3          1 =>1=>1=>2
         2          2          1 =>1=>2
         1          3          2 =>1=>2=>1
         2          3          2 =>1=>2=>2
         2          1            =>2
         1          2          2 =>2=>1
         1          3          1 =>2=>1=>1
         2          3          1 =>2=>1=>2
         2          2          2 =>2=>2
         1          3          2 =>2=>2=>1
         2          3          2 =>2=>2=>2

14 rows selected.

从那个例子中我很清楚,但我很难用简洁的语言表达出来。

【问题讨论】:

    标签: oracle connect-by hierarchical-query


    【解决方案1】:

    除了 "level

    您可能想要添加“and prior a.id = a.id”。这将导致 Oracle 抱怨循环(因为 Oracle 在看到 PRIOR 列中的相同值时决定达到一个循环)。反过来,这可以通过添加第三个条件来解决,通常是“并且之前的 sys_guid() 不为空”。

    已编辑;原始答案引用了 NOCYCLE,在使用“先前的 sys_guid() 不为空”方法时不需要。)

    最近在 OTN 上讨论过这个问题:https://community.oracle.com/thread/3999985

    此处讨论的相同问题:https://community.oracle.com/thread/2526535

    【讨论】:

    • 感谢 mathguy 和 Boneist。正如我所说,我不是在寻找解决方案,我只是想了解导致它的原因。我想我会玩一下通过路径连接,看看我能不能弄明白......
    • @MattKnowles - 我没有将其作为对您的查询的修复 - 我将其作为(部分)您所看到的解释。如果您关注这些链接,以及从那里获得更多链接,您将看到讨论几乎是关于“这是如何工作的”,而不是“它如何用于解决特定问题”。正如您计划做的那样,自己玩它肯定也会有很大帮助。祝你好运!
    • 再次感谢您抽出宝贵时间,mathguy。
    【解决方案2】:

    为了说明 Mathguy 的答案,您在 CONNECT BY 子句中遗漏了一些谓词:

    with alpha as (
            select 1 as id
                from dual
        ),
        beta as (
            select 1 as alpha_id,
                    1 as beta_no
                from dual
            union all
            select 1 as alpha_id,
                    2 as beta_no
                from dual
        )
    select a.id,
           b.beta_no,
           level as the_level
    from   alpha a
           inner join beta b
             on b.alpha_id = a.id
    connect by level <= 4
               AND PRIOR a.id = a.id
               AND PRIOR b.beta_no = b.beta_no
               AND PRIOR sys_guid() IS NOT NULL
    order by a.id,
             b.beta_no,
             LEVEL;
    
            ID    BETA_NO  THE_LEVEL
    ---------- ---------- ----------
             1          1          1
             1          1          2
             1          1          3
             1          1          4
             1          2          1
             1          2          2
             1          2          3
             1          2          4
    

    另一种方法是使用递归 with 子句:

    with alpha as (
            select 1 as id
                from dual
        ),
        beta as (
            select 1 as alpha_id,
                    1 as beta_no
                from dual
            union all
            select 1 as alpha_id,
                    2 as beta_no
                from dual
        ),
        multiply (id, beta_no, rn) AS (SELECT a.id,
                                              b.beta_no,
                                              1 rn
                                       FROM   alpha a
                                              INNER JOIN beta b
                                                ON a.id = b.alpha_id
                                       UNION ALL
                                       SELECT ID,
                                              beta_no,
                                              rn + 1
                                       FROM   multiply
                                       WHERE  rn + 1 <= 4)
    SELECT ID,
           beta_no,
           rn AS the_level
    FROM   multiply
    order by id,
             beta_no,
             rn;
    
            ID    BETA_NO  THE_LEVEL
    ---------- ---------- ----------
             1          1          1
             1          1          2
             1          1          3
             1          1          4
             1          2          1
             1          2          2
             1          2          3
             1          2          4
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-03-04
      • 2015-01-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-08-10
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多