Oracle Connect By似乎产生了太多行

时间:2017-01-11 00:09:20

标签: oracle connect-by hierarchical-query

Oracle Database 12c企业版12.1.0.2.0版

我希望我只是遗漏了一些东西,但是如果我在没有“connect by”的情况下运行这个查询,我会得到2行。当我添加“按级别连接< = 4”时,我希望将这2行中的每一行都添加4次。实际结果不同。

任何人都可以帮我理解这里发生的事情吗?我不是在寻找一个只能重复每行4次的解决方案 - 我已经知道了。我只是想了解发生了什么以及为什么。

    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
     
  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.
     

选择了30行

非常感谢mathguy。他在下面的答案中提供的第二个链接正是我正在寻找的。具体做法是:

public final class ConfigCache {

private static final MultiKeyMap configCache = new MultiKeyMap();

@Autowired
    private ConfigDao dao;

    @PostConstruct
    public void init() {

        Map<String, Collection<Configuration>> map = null;
        try {
            if (configurationCache != null || configurationCache.isEmpty()) {

                map = dao.loadConfigurations();
                map.forEach((k, v) -> {
                    v.forEach((c) -> {
                        configCache.put(k, c.getAttributeName(), c.getAttributeValue());
                    });
                });
            }

        } catch (DaoException e) {
            throw new RuntimeException(e);
        }
    }

    public Object getValue(String k1, String k2) {
        return configurationCache.get(k1, k2);
    }

    @PreDestroy
    public void clearCache() {
        if (configCache != null) {
            configCache.clear();
        }
    }

}

我从这个例子中可以清楚地看到,但我很难简洁地说出来。

2 个答案:

答案 0 :(得分:2)

除了&#34; level&lt; = 4&#34;之外的任何条件,原始表,视图等中的每一行(在这种情况下来自连接)将在2级产生两行,然后是4 3级更多行,4级更多8行。&#34; Connect by&#34;本质上是一系列连接,如果PRIOR运算符没有条件,则表示正在进行交叉连接。

您可能想要添加&#34;并且先前a.id = a.id&#34;。这将导致Oracle抱怨周期(因为Oracle在看到PRIOR列中的相同值时决定达到一个周期)。反过来,这通过添加第三个条件来解决,通常是&#34;并且先前的sys_guid()不是空的&#34;。

已编辑;原始答案引用了NOCYCLE,使用&#34时不需要;之前的sys_guid()不是null&#34;方法。)

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

这里讨论了同样的问题:https://community.oracle.com/thread/2526535

答案 1 :(得分:0)

为了说明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

另一种方法是使用recursive 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