web-dev-qa-db-ja.com

テーブルのCONNECT BY LEVELが余分な行を返すのはなぜですか?

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

列LVLの値が1である表Aの各行と、列LVLが2である表Aの各行に3行

 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行を返す理由、またはID列の各値に対してLVLが2で3行があり、LVLが1であるのは1行だけである理由がわかりません。

「接続」されているレベルの数を3に増やす 13行を返す IDの各値に対して。 LVLが1の場合1、LVLが2の場合3、LVLが3の場合9.

ただし、これらのクエリは次のようになり、6行が返されます。

select id, lvl
  from ( select level  as lvl
           from dual
        connect by level  <= 2
                )
 cross join a
 order by id, lvl

documentation は、何が起こるべきかを説明する上で、私には特に明確ではありません。これらの権限で何が起きているのですか?最初の2つのクエリが3番目のクエリと同じではないのはなぜですか?

14
Ben

最初のクエリでは、レベルだけで接続します。したがって、レベル<= 1の場合、各レコードを1回取得します。レベル<= 2の場合、各レベル1回(レベル1の場合)+ N回(Nはテーブル内のレコード数)を取得します。結果を制限する他の条件がなくても、レベルに達するまでテーブルからすべてのレコードを選択するだけなので、クロスジョインのようです。レベル<= 3の場合、これらの結果ごとにこれが再度行われます。

したがって、3つのレコードの場合:

  • レベル1:3レコード(すべてレベル1)
  • Lvl 2:レベル1の3レコード+レベル2 = 12の3 * 3レコード
  • Lvl 3:3 + 3 * 3 + 3 * 3 * 3 = 39(実際、各13レコード)。
  • Lvl 4:パターンを見始めましたか? :)

実際にはクロスジョインではありません。クロス結合は、このクエリ結果にレベル2のレコードのみを返しますが、この接続では、レベル1のレコードとレベル2のレコードを取得するため、結果は単なる3ではなく3 + 3 * 3になります。 3 * 3レコード。

14
GolezTrol

connect by句とprior演算子なしでstart withを使用する場合、子行を親行に結合することに制限はありません。そして、この状況で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
14
Nick Krasnov

lEVELが1行のデュアルテーブルに分離されているため、最終クエリを他のクエリと比較するときに、リンゴとオレンジを比較しています。

このクエリを検討してみましょう:

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

つまり、テーブルセットから始めます(*から選択)。次に、返された各行に対して、この行を前の行に接続します。 connect byで結合を定義していないので、これは実質的にデカルト結合です。したがって、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行(元の「レベル1」行3行とデカルト集合)を取得する理由です。

出力行数= rowcount +(rowcount ^ 2)

最後のクエリでは、これにレベルを分離しています

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

もちろん2行を返します。次に、これを元の3行にデカルトし、6行を出力として提供します。

1
DazzaL

以下の手法を使用して、この問題を克服できます。

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
0
AlexiWilius