2016-07-27 1 views
0

두 개의 매개 변수를 사용하는 테이블 반환 함수를 작성해야합니다.재귀 공통 테이블 표현식은 어떻게 작동합니까?

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

함수는 두 파라미터 번호를 포함하고 @start_number@end_number 사이의 번호를 포함하는 테이블을 반환한다.

이 쿼리는 output.But 원하는 부여합니다
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 

, 내가 endstart에서 설명이 필요,이 라인이 작동하는 방법을 여기 max recursion의 목적은 무엇인가? 여기

코드인가?

+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은 중첩 쿼리와 유사하며 임시 결과 집합입니다. 가장 큰 차이점은 자체 참조 될 수 있다는 것입니다 (귀하의 경우처럼). 하나의 열만있는 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 개 값을 생성하려고한다면,이 오류를 얻을 것이다 :

The statement terminated. The maximum recursion 10000 has been exhausted before statement completion.

주, 당신의 CTE 내부에 위치해야합니다 재귀를 제한 필터, 안 이 경우 CTE를 사용하면 엔진은 다음 일치 값을 찾기 위해 CTE를 반복하여 계속 진행하지만 CTE는 그대로 무한하며 오류가 발생합니다.

나머지 코드는 매우 간단합니다. 결과 양식 CTE가 @numbers 테이블 변수에 삽입 된 다음 간단히 선택됩니다. 그렇지 사용 (및 OPTION 절 내에서 사용될 수 없음)으로

@max_recursion 변수가 제거 될 수있다.