を利用した部分を除外して、再帰的共通のテーブル式
-
16-10-2019 - |
質問
なぜ、以下のクエリを返し無限の行?この期待に EXCEPT
条項は終了の再帰..
with cte as (
select *
from (
values(1),(2),(3),(4),(5)
) v (a)
)
,r as (
select a
from cte
where a in (1,2,3)
union all
select a
from (
select a
from cte
except
select a
from r
) x
)
select a
from r
ってことながら答えようと、 質問 にスタックオーバーフロー.
解決
見る マーティン・スミスの答え の現在のステータスの詳細について EXCEPT
再帰CTEで。
あなたが見ていたものとその理由を説明するために:
ここでは、テーブル変数を使用して、アンカー値と再帰アイテムをより明確に区別します(セマンティックは変更されません)。
DECLARE @V TABLE (a INTEGER NOT NULL)
INSERT @V (a) VALUES (1),(2)
;
WITH rCTE AS
(
-- Anchor
SELECT
v.a
FROM @V AS v
UNION ALL
-- Recursive
SELECT
x.a
FROM
(
SELECT
v2.a
FROM @V AS v2
EXCEPT
SELECT
r.a
FROM rCTE AS r
) AS x
)
SELECT
r2.a
FROM rCTE AS r2
OPTION (MAXRECURSION 0)
クエリプランは次のとおりです。
実行は計画の根本(Select)から始まり、コントロールはツリーを渡してインデックススプール、連結、そしてトップレベルのテーブルスキャンに渡されます。
スキャンからの最初の行はツリーを通過し、(a)スタックスプールに保存され、(b)クライアントに返されます。最初にどの行が定義されていませんが、議論のために、それが値{1}を持つ行であると仮定しましょう。したがって、最初に表示される行は{1}です。
コントロールは再びテーブルスキャンに渡ります(連結演算子は、次の入力を開く前に、最も外側の入力からすべての行を消費します)。スキャンは2行目(値{2})を発し、これは再びツリーを渡して、スタックに保存され、クライアントに出力されます。クライアントは、シーケンス{1}、{2}を受信しました。
LIFOスタックの上部が左側にあるコンベンションを採用すると、スタックには{2、1}が含まれています。コントロールが再びテーブルスキャンに渡されると、それ以上の行が報告されず、コントロールは連結演算子に戻ります。初めて。
内側の結合は、外側の入力にテーブルスプールを呼び出します。これは、スタック{2}から上の行を読み取り、ワークテーブルから削除します。スタックには{1}が含まれるようになりました。
外側の入力で行を受け取ったため、内側の結合は、左のアンチセミ結合(LASJ)への内側の入力を制御します。これにより、外側の入力から行が要求され、制御をソートに渡します。ソートはブロッキングイテレーターであるため、テーブル変数からすべての行を読み取り、昇順で並べ替えます。
したがって、このソートによって放出される最初の行は、値{1}です。 LASJの内側は、再帰メンバーの現在の値(スタックから外れたばかりの値)、つまり{2}を返します。 LASJの値は{1}および{2}であるため、値が一致しないため、{1}は放出されます。
この行{1}は、クエリプランツリーをインデックス(スタック)スプールにフローし、スタックに追加され、{1、1}が含まれ、クライアントに放出されます。クライアントは、シーケンス{1}、{2}、{1}を受信しました。
コントロールは連結に戻り、内側を下って戻って(前回は行を返し、再び行うかもしれません)、内側の結合を通ってLASJに向かいます。それは再び内部入力を読み取り、ソートから値{2}を取得します。
再帰メンバーはまだ{2}なので、今回はLASJが{2}と{2}を見つけて、列が放出されません。内側の入力(ソートは行が外れている)にこれ以上行が見つかりません。コントロールは内側の結合に戻ります。
内側の結合は外側の入力を読み取り、値{1}がスタック{1、1}からポップされ、スタックを{1}だけで残します。テーブルスキャンの新しい呼び出しから値{2}を使用してプロセスが繰り返され、LASJテストに合格してスタックに追加され、クライアントに渡されます。 {1}、{2} ...そして、私たちは行きます。
私のお気に入り 説明 再帰的なCTEプランで使用されるスタックスプールは、クレイグフリードマンのものです。
他のヒント
のボル説明の再帰的CTEs の意味の再帰的として実行している。
- 分割の線膨張係数で表現へのアンカーおよび再帰的ます。
- のアンカー委員の最初の呼び出しまたは結果セット(T0).
- を再帰的員はTiとして入力およびTi+1として出力されます。
- 繰り返しステップ3までの空のセットが返されます。
- の結果を返すセットです。これは、EUのすべてのT0をTn.
注上記は、 論理 ます。 の物理的順の操作を行うことができます落としていま
適用することのできる熱膨張が期待される無限ループ以下のパターン
+-----------+---------+---+---+---+
| 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キウイの優れた回答 でもなぜことではありませんので、全体に話が集まってきている負荷のもののスタックトなので処理されます。
アンカーを発行
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
ができます。
追加: Microsoftていた私 接続の声 として以下の
ジャック's"推測が正しい:すべての構文エラー再帰的な参照は実際不可に
EXCEPT
条項.計画していまこのバグは、今後のサービスです。の 一方、私はあなたを避ける再帰的に参照EXCEPT
条項.に制限再帰を超
EXCEPT
まずは、ANSI SQL標準 を含むこの制限以来、再帰した 導入した(1999年だと思い).ありが広が契約上 何を意味する再帰過EXCEPT
るとともに "unstratified否定"と宣言語などのSQL.に ほかにも難しいものでない場不可)の実施など 意味論の有効(当データベース)RDBMS システム。
によって最終的に実施した2014年のためのデータベース との互換レベルの120以上.
再帰的に参照EXCEPT節を生成エラーを遵守し、ANSI SQL標準装備。