2016-07-27 18 views
0

必要条件は、2つのパラメータをとるテーブル値関数を記述することです。再帰的な共通テーブル式はどのように機能しますか?

@start_number (a integer value) 
@end_number (a integer value) 

関数は、両方のパラメータ番号を含む、@start_number@end_number間の数値を含むテーブルを返します。ここで

はコードです:?

Declare @start_number int 
Declare @end_number int 
Declare @max_recursion int 

Set @start_number = 10 
Set @end_number = 100 
Set @max_recursion = (@end_number - @start_number) 

Declare @numbers table(number int) --start 
;with numbers(number) as 
(
select @start_number as number 
union all 
select number + 1 from numbers where number between @start_number and @end_number - 1 
) 

insert into @numbers(number) 
select number from numbers option(maxrecursion 10000) 
select number from @numbers  --end 

クエリがoutput.But希望与える、私はこれらの行は、ここでmax recursionの目的は何働いているか、startからendへの説明が必要ですか?

+0

なぜあなたはこれの著者に尋ねないのですか? –

+0

私は、あなたが気づいていない場合は、著者に依頼し、別のアプローチを提案しています。 – FDavidov

+0

@FDavidov私はその質問がザヒドのためだと思っています... –

答えて

1
-- 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句内では使用できません)。

関連する問題