如果我在CTE的递归部分中没有联接,那么每次递归只能得到一行,为什么?
在SQL Server 2016和Azure SQL数据库上经过测试的代码:
DECLARE @Number TABLE (Number INT);
INSERT INTO @Number (Number)
VALUES (1), (2);
;WITH _cte AS
(
SELECT Number
FROM @Number
UNION ALL
SELECT _cte.Number
FROM _cte
)
SELECT *
FROM _cte
OPTION (MAXRECURSION 2); -- just call recursive part twice to see the issue
结果是,我在每个递归/深度中都得到了数字2
。
我希望当前行在每次递归中都会重复,因此行数呈指数增长
预期产量
Number
--------------------
1 -- from anchor
2
1 -- first recursion
2
1 -- second recursion
2
1
2
实际输出:
Number
--------------------
1 -- from anchor
2
2 -- first recursion
2 -- second recursion
答案 0 :(得分:2)
根据一些测试,似乎SQL递归首先从初始查询返回的最后一行开始深度进行。到达MAXRECURSION
后,查询会以错误(例如The statement terminated. The maximum recursion 2 has been exhausted before statement completion.
)终止,并返回错误之前到达的所有结果。您可以通过在插入语句中插入2,1而不是1,2,或在您的@Number
表中插入1,2,3来验证这一点。如果您将1,2,3插入@Number
,则返回的结果将是
1 -- From anchor
2 -- From anchor
3 -- From anchor
3 -- 1st recursion from last row of anchor query
3 -- Recursion from the row from the line above this (2nd recursion)
-- Query terminates after MAXRECURSION reached on an item and does not attempt recursion on 1 or 2
通常,当使用递归时,您可以使用where语句中的某些条件或联接中的on条件将CTE连接到自身或其他表,这些条件会限制基于可用数据的递归(而不仅仅是通过相同的元素)。例如(使用与您的问题相同的@Number
表):
DECLARE @Number TABLE (Number INT);
INSERT @Number
(
Number
)
VALUES (1),
(2);
WITH _cte2
AS
(SELECT
Number
,0 as 'RecursionCount'
FROM
@Number
UNION ALL
SELECT
Number
,RecursionCount + 1
FROM
_cte2
WHERE
RecursionCount <= 1
)
SELECT * FROM _cte2 OPTION (MAXRECURSION 2);
在上面的示例中,查询将在where语句中限制其自身的递归,并且永远不会达到MAXRECURSION,因此查询将能够完成。您还将注意到,返回结果的顺序证实了我的怀疑,即递归是深度优先,从最后一项开始:
Number RecursionCount
1 0
2 0
2 1
2 2
1 1
1 2
答案 1 :(得分:0)
我将您的代码更改为:
with
_cte as (
SELECT num, 0 iteration
FROM @Number
UNION ALL
SELECT num, iteration + 1
FROM _cte
where iteration <= 3 -- comment this line out and compare
)
SELECT *
FROM _cte
--OPTION (MAXRECURSION 2); -- comment this line out and compare as well
然后我在注释“ where迭代<= 3”时将结果与结果进行了比较。我花了一段时间才意识到,但是结果的排序不是我期望的。
我认为,当遇到最大循环错误时,或者当您选择切断最大递归的选项时,就会以某种方式切断您将在第7-10行中找到的后者的结果。