-- table variable declaration
Declare @numbers table(number int) --start
-- CTE declaration
;with numbers(number) as
(-- CTE body
-- anchor
select @start_number as number -- [a]
union all
-- recursive call to itself
select number + 1 from numbers -- [r]
-- recursion limit
where number between @start_number and @end_number - 1
)
insert into @numbers(number)
-- insert into @numbers table all values from CTE
select number from numbers option(maxrecursion 10000)
-- pretty obvious select
select number from @numbers --end
テーブル変数は、通常のテーブルとほぼ同じように動作します。 テンポラリテーブルとテーブル変数の違いについてthis questionまたはmsdnを参照してください。
CTEは、ネストされたクエリ、一時的な結果セットと似ています。主な相違点は、(あなたの場合のように)自己参照することができるということです。 1列のみのCTEを宣言する場合はnumber
です。カラムを手動で指定する必要はありません。これはrecursive CTEです - 番号を選択し、それ自身を+1に追加します。したがって、後続の各行は前の行に+1
を持ちます。 CTEアンカーから選択するとselect @start_number as number
が実行されます。すべてが連結されているよりも、フォーム自体が返されています(+1が追加されています)。
のは、CTE内のステップごとに行こう:
on [a] return 1
on [r] add +1 to everything from self ([a] and [r]):
on [a] return 1
on [r] add +1 to everything from self ([a] and [r]):
on [a] return 1
on [r] add +1 to everything from self ([a] and [r]):
on [a] return 1
on [r] add +1 to everything from self ([a] and [r]):
...
だからあなたの結果セットが(各ネストレベルが{
と}
内にある)である:
上
{1, {1, {1, {1, ...} +1 } +1 } +1 }
どこ{1} +1 => {2}
、{1, {1} +1 } +1 => {1, 2} +1 => {2, 3}
ので、
このクエリを制限しない場合、ネスティングは無限になります。そのため、recursion limit
が表示されます。エンジンは無限のクエリを単にフィルタリングし、その後の選択ではフィルタに一致しない値を取得するので、空の結果セットが返されます。たとえば、10少ないし値をフィルタ:
....
on [a] return 1 -- will result 8, match
on [r] add +1 to everything from self ([a] and [r]):
on [a] return 1 -- will result in 9, match
on [r] add +1 to everything from self ([a] and [r]): -- (STOP)
on [a] return 1 -- will result in 10, not match
-- nothing else will be queried as on (STOP) empty result returned
-- so, recursion stopped
注意を、あなたは再帰呼び出し、例えばで正しくフィルタリングあればということ
where number between @start_number + 1 and @end_number - 1
非常に最初の再帰呼び出しを使用すると、フィルタに一致していない、あなた@start_number
に戻り、何の再帰が発生しないこと。
実際には、フィルタ
where number between @start_number and @end_number - 1
が過剰です。以前の値に+1
を追加すると、両方のケースでは、フィルタが@end_number
とは一致しません、
where number < @end_number
注意を簡略化することができます。あなたは@start_number
(アンカー)で始まり、再帰とを連結するように、それはそれは100で、デフォルトで
{ @start_number, ..., @end_number -1 } +1
結果はselect文option(maxrecursion 10000)
オーバーライドデフォルトの最大再帰レベルで
{ @start_number, @start_number +1, ..., @end_number -1 +1 }
-- ^^^^^^^^^^^^^ - anchor
-- recursion - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Hint(だろう返します有効な値は[0..32767]です)。だからあなたの特定の機能は、10000個の値に制限されており、あなたはもっとして10000個の値を生成しようとする場合は、このエラーを取得します:
The statement terminated. The maximum recursion 10000 has been exhausted before statement completion.
注意、あなたのCTEの内側に配置する必要があります再帰を制限するフィルタではなく、あなたをそのCTEを使用すると、エンジンは次の一致する値を探すためにCTEを繰り返し処理しますが、CTEは文字通り無限大でエラーが発生します。
残りのコードは非常に単純です - 結果フォームCTEが01テーブル変数に挿入され、単純に選択されました。
変数@max_recursion
は使用されていないので削除できます(OPTION
句内では使用できません)。
なぜあなたはこれの著者に尋ねないのですか? –
私は、あなたが気づいていない場合は、著者に依頼し、別のアプローチを提案しています。 – FDavidov
@FDavidov私はその質問がザヒドのためだと思っています... –