В отличие от SQL из других языков программирования, структура рекурсивного запроса выглядит довольно странно. Пройдите через это шаг за шагом, и это, кажется, разваливается.
Рассмотрим следующий простой пример:
CREATE TABLE #NUMS
(N BIGINT);
INSERT INTO #NUMS
VALUES (3), (5), (7);
WITH R AS
(
SELECT N FROM #NUMS
UNION ALL
SELECT N*N AS N FROM R WHERE N*N < 10000000
)
SELECT N FROM R ORDER BY N;
Давайте пройдемся по нему.
Сначала выполняется элемент привязки, и набор результатов помещается в R. Таким образом, R инициализируется как {3, 5, 7}.
Затем выполнение падает ниже UNION ALL, и рекурсивный член выполняется впервые. Он выполняется на R (то есть на R, который у нас есть на данный момент: {3, 5, 7}). Это приводит к {9, 25, 49}.
Что это делает с этим новым результатом? Добавляет ли он {9, 25, 49} к существующему {3, 5, 7}, маркирует результирующее объединение R, а затем продолжает рекурсию оттуда? Или он переопределяет R как только этот новый результат {9, 25, 49} и делает все объединение позже?
Ни один из вариантов не имеет смысла.
Если R теперь {3, 5, 7, 9, 25, 49} и мы выполним следующую итерацию рекурсии, то получим {9, 25, 49, 81, 625, 2401} и мы потерял {3, 5, 7}.
Если R теперь только {9, 25, 49}, то у нас есть проблема с неправильной маркировкой. Под R понимается объединение результирующего набора якорных членов и всех последующих рекурсивных результирующих наборов членов. Принимая во внимание, что {9, 25, 49} является только компонентом R. Это не полный R, который мы накопили до сих пор. Поэтому записывать рекурсивный член как выбор из R не имеет смысла.
Я, безусловно, ценю то, что @Max Vernon и @Michael S. подробно описали ниже. А именно, что (1) все компоненты создаются до предела рекурсии или нулевого набора, а затем (2) все компоненты объединяются вместе. Вот как я понимаю рекурсию SQL на самом деле работать.
Если бы мы проектировали SQL, возможно, мы бы применили более четкий и явный синтаксис, примерно так:
WITH R AS
(
SELECT N
INTO R[0]
FROM #NUMS
UNION ALL
SELECT N*N AS N
INTO R[K+1]
FROM R[K]
WHERE N*N < 10000000
)
SELECT N FROM R ORDER BY N;
Вроде как индуктивное доказательство в математике.
Проблема с рекурсией SQL в ее нынешнем виде заключается в том, что она написана в замешательстве. То, как написано, говорит, что каждый компонент формируется путем выбора из R, но это не означает полный R, который был (или, кажется, был) построен до сих пор. Это просто означает предыдущий компонент.