永久再帰処理の問題は循環データだけではありません。クエリー データが循環しない場合でも、意味的に不正なクエリーによって永久に再帰する場合があります。永久ループの原因となる意味的に不正な結合条件は独特の問題です。そのような条件の部分的なリストには次のものが含まれます。
- 不正な列を結合する。
- 結合から不正な列を選択する。
- 複数の結合条件で、AND演算子の代わりにOR演算子を使用する。
- 結合テーブルに相関名を付けた後で、間違って結合テーブルの元の名前を参照する。
この場合、システムはクエリーを2つのテーブルの結合ではなく、3つのテーブルの結合を指定するものと解釈します。その結果、「3つ目」のテーブルには結合条件がないため、相互結合が作成されます。
- 結合条件を重複指定する。
次の例は、述部rec.depth <= 1000によってのみ限定される重複したケースを図示しています。このトートロジーは、シード クエリーのWHERE条件がcol_1の値が2である1行だけを返すのに対し、再帰的クエリーのWHERE条件がcol_1の値が2または3のどちらかである行のみを返すことによって生じます。再帰処理のたびにcol_1の値が2である行が生成されるので、条件WHERE rec.depth =1000がなければ無限ループになるところです。
次のデータを持つテーブルTがあるとします。
T | |
---|---|
Col_1 | Col_2 |
2 | 3 |
4 | 5 |
6 | 7 |
8 | 9 |
次に、以下の再帰的ビューを作成します。
CREATE RECURSIVE VIEW rec (a, depth) AS ( SELECT col_1, 0 AS depth FROM t WHERE col_1 = 2 UNION ALL SELECT a, rec.depth + 1 FROM t, rec WHERE t.col_1 IN (2, 3) AND rec.depth <= 1000);
このビューに対する次のクエリーは、その値がすべて2である1,001個の行を持つ結果セットを生成します。再帰処理はクエリーがその限界値に達した場合にのみ停止します。限界が設定されない場合、ディスク領域のスプールが使い果たされるまでクエリーは続きます。
SELECT a FROM rec;
クエリーの結果セットは次のようになります。省略記号は994の追加行を示し、その値はそれぞれ2です。
A |
---|
2 |
2 |
2 |
2 |
2 |
… |
2 |
同じ問題が、同じテーブルtに基づく次の再帰的ビュー定義でも生じます。この再帰的ビューも重複した検索条件によって定義されますが、前の例で指定したIN句の代わりにEXISTS句を指定します。
CREATE RECURSIVE VIEW rec (a, depth) AS ( SELECT col_1, 0 AS depth FROM t WHERE col_1 = 2 AND EXISTS (SELECT col_1 FROM t) UNION ALL SELECT a, rec.depth + 1 FROM t, rec WHERE rec.a = t.col_1 AND rec.depth <= 1000);
この再帰的ビューに対する次のクエリーは、IN句の例と同じ結果セットを生成します。 1,001行はすべて値2を持ちます。
SELECT a FROM rec;