-- 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).
Давайте идти шаг за шагом в КТР:
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
является чрезмерным. Это может быть упрощено до
where number < @end_number
Примечания, в обеих случаях фильтра не будет соответствовать @end_number
, как добавляет +1
к предыдущему значению.Так как вы начинаете с @start_number
(якорь) и конкатенации с с помощью рекурсии, которая возвращает
{ @start_number, ..., @end_number -1 } +1
результат будет
{ @start_number, @start_number +1, ..., @end_number -1 +1 }
-- ^^^^^^^^^^^^^ - anchor
-- recursion - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Hint в выберите заявление option(maxrecursion 10000)
ручной коррекции максимального по умолчанию уровня рекурсии (по умолчанию это 100 , действительными значениями являются [0..32767]). Таким образом, ваша конкретная функция ограничена до 10000 значений, и если вы будете пытаться произвести более 10000 значений, вы получите эту ошибку:
The statement terminated. The maximum recursion 10000 has been exhausted before statement completion.
Примечание, фильтр, который ограничивает рекурсию должны быть размещены внутри КТР, не там, где используйте CTE, так как в этом случае движок продолжит итерацию через CTE, ища следующее значение соответствия, но ваш CTE будет буквально бесконечным и произойдет ошибка.
Остальная часть кода довольно проста - форма результата CTE вставлена в таблицу @numbers
и затем просто выбрана.
Переменная @max_recursion
может быть удалена, поскольку она не используется (и не может использоваться внутри статьи OPTION
).
Почему бы вам не попросить автора об этом? –
Я спрашиваю автора и предлагаю другой подход, если вы его не заметили. – FDavidov
@FDavidov Я думаю, что вопрос был для Zahid ... –