14

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の各行に1つの行があり、列LVLの値は1であり、テーブルAの各行に3つあり、列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

ID列の各値に対して、これらのクエリが12行を返す理由、またはLVLが2の行が3つあり、LVLが1の行が1つしかない理由がわかりません。

「接続」されているレベルの数を3に増やすと、IDの値ごとに13行が返されます。1(LVLが1の場合)、3(LVLが2の場合)、および9(LVLが3の場合)。これは、返される行が、LVLの値から1を引いた値の表Aの行数であることを示しているようです。

ただし、これらのクエリは次のクエリと同じで、6行が返されます。

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

何が起こるべきかを説明する上で、ドキュメントは私には特に明確ではありません。これらの力で何が起こっているのか、そしてなぜ最初の2つのクエリが3番目のクエリと同じではないのですか?

4

4 に答える 4

16

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

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

  • Lvl 1: 3 レコード (すべてレベル 1 を持つ)
  • レベル 2: レベル 1 を持つ 3 つのレコード + レベル 2 を持つ 3*3 レコード = 12
  • Lvl 3: 3 + 3*3 + 3*3*3 = 39 (実際、それぞれ 13 レコード)。
  • Lv 4: パターンが見え始めた? :)

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

于 2012-11-24T12:35:59.170 に答える
16

を句と演算子connect byなしで使用すると、子行を親行に結合することに制限はありません。そして、この状況で Oracle が行うことは、行を上位レベルのすべての行に接続することによって、考えられるすべての階層順列を返します。start withprior

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
于 2012-11-24T12:36:43.573 に答える
1

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

このクエリを考えてみましょう:

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

つまり、テーブル セットから始めます (* From a を選択)。次に、返された行ごとに、この行を前の行に接続します。connect byで結合を定義していないため、これは実質的にデカルト結合であるため、(1,2,3) 1の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 行が出力されます。

于 2012-11-24T12:32:56.630 に答える
0

この問題を解決するには、以下の手法を使用できます。

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
于 2016-01-09T08:43:46.463 に答える