-- 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
변수가 제거 될 수있다.
왜이 책의 저자에게 질문하지 않습니까? –
필자는 눈치 채지 못했을 때 저자에게 묻고 다른 접근법을 제안하고있다. – FDavidov
@FDavidov 나는 그 질문이 자히드를위한 것이라고 생각한다 ... –