再帰CTEのBOL記述では、再帰実行のセマンティクスを次のように説明しています。
- CTE式をアンカーメンバーと再帰メンバーに分割します。
- 最初の呼び出しまたはベース結果セット(T0)を作成するアンカーメンバーを実行します。
- Tiを入力、Ti + 1を出力として再帰メンバーを実行します。
- 空のセットが返されるまで、手順3を繰り返します。
- 結果セットを返します。これはT0〜TnのUNION ALLです。
上記は論理的な説明です。操作の物理的な順序は、ここに示すように多少異なる場合があります
これをCTEに適用すると、次のパターンの無限ループが予想されます
+-----------+---------+---+---+---+
| Invocation| Results |
+-----------+---------+---+---+---+
| 1 | 1 | 2 | 3 | |
| 2 | 4 | 5 | | |
| 3 | 1 | 2 | 3 | |
| 4 | 4 | 5 | | |
| 5 | 1 | 2 | 3 | |
+-----------+---------+---+---+---+
なぜなら
select a
from cte
where a in (1,2,3)
アンカー式です。これは明らかに返し1,2,3
てT0
その後、再帰式が実行されます
select a
from cte
except
select a
from r
1,2,3
出力もたらす入力など4,5
のようにT1
、次に返され再帰の次のラウンドのためにその背面を接続する1,2,3
ように無期限と。
しかし、これは実際に起こることではありません。これらは、最初の5回の呼び出しの結果です
+-----------+---------+---+---+---+
| Invocation| Results |
+-----------+---------+---+---+---+
| 1 | 1 | 2 | 3 | |
| 2 | 1 | 2 | 4 | 5 |
| 3 | 1 | 2 | 3 | 4 |
| 4 | 1 | 2 | 3 | 5 |
| 5 | 1 | 2 | 3 | 4 |
+-----------+---------+---+---+---+
使用OPTION (MAXRECURSION 1)
して上向きに調整することにより1
、連続する各レベルが出力1,2,3,4
との 間で継続的に切り替わるサイクルに入ることがわかります1,2,3,5
。
このブログ投稿で@Quassnoiが説明したように。各呼び出しが行っているかのように観察された結果のパターンである場合、前の呼び出しから最後の行です。(1),(2),(3),(4),(5) EXCEPT (X)
X
編集:SQL Kiwiの優れた答えを読んだ後、これが発生する理由と、処理されないものがまだスタックに残っているという点でこれがすべてではないことが明らかです。
1,2,3
クライアントスタックの内容にアンカーエミッター3,2,1
スタックから3ポップ、スタックの内容 2,1
LASJは1,2,4,5
、スタックの内容を返します5,4,2,1,2,1
スタックから5ポップ、スタックの内容 4,2,1,2,1
LASJは1,2,3,4
スタックの内容を返します4,3,2,1,5,4,2,1,2,1
4スタックからポップ、スタックの内容 3,2,1,5,4,2,1,2,1
LASJは1,2,3,5
スタックの内容を返します5,3,2,1,3,2,1,5,4,2,1,2,1
スタックから5ポップ、スタックの内容 3,2,1,3,2,1,5,4,2,1,2,1
LASJは1,2,3,4
スタックの内容を
返します4,3,2,1,3,2,1,3,2,1,5,4,2,1,2,1
再帰メンバーを論理的に同等の(重複/ NULLがない場合)式に置き換えようとした場合
select a
from (
select a
from cte
where a not in
(select a
from r)
) x
これは許可されておらず、「サブクエリでは再帰的参照は許可されていません」というエラーが発生します。そのため、おそらくEXCEPT
この場合でも許可されているのは見落としです。
追加:
マイクロソフトは、次のように接続フィードバックに応答しました
ジャックの推測は正しい:これは構文エラーだったはずです。実際、再帰的参照はEXCEPT
句で許可されません。今後のサービスリリースでこのバグに対処する予定です。それまでは、EXCEPT
節内の再帰的な参照を避けることをお勧めします。
再帰を制限する場合EXCEPT
、ANSI SQL標準に従います。これには、再帰が導入されて以来(1999年に私が信じている)この制限が含まれています。EXCEPT
SQLなどの宣言型言語での再帰(「階層化されていない否定」とも呼ばれます)のセマンティクスがどうあるべきかについて、広範な合意はありません。さらに、RDBMSシステムでこのようなセマンティクスを(合理的なサイズのデータベースに対して)効率的に実装することは(不可能ではないにしても)難しいことで有名です。
そして、120以上の互換性レベルを持つデータベースに対して、2014年に最終的な実装が行われたように見えます。
EXCEPT句の再帰的参照は、ANSI SQL標準に準拠したエラーを生成します。