質問

なぜ、以下のクエリを返し無限の行?この期待に 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)

クエリプランは次のとおりです。

Recursive CTE Plan

実行は計画の根本(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 の意味の再帰的として実行している。

  1. 分割の線膨張係数で表現へのアンカーおよび再帰的ます。
  2. のアンカー委員の最初の呼び出しまたは結果セット(T0).
  3. を再帰的員はTiとして入力およびTi+1として出力されます。
  4. 繰り返しステップ3までの空のセットが返されます。
  5. の結果を返すセットです。これは、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,41,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標準装備。

ライセンス: CC-BY-SA帰属
所属していません dba.stackexchange
scroll top