【问题标题】:cte recursive part only returns one rowcte 递归部分只返回一行
【发布时间】:2018-11-09 15:16:20
【问题描述】:

如果我的 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

【问题讨论】:

  • 编写的代码会抛出错误。
  • 感谢@MartinSmith - 该链接证实了我对答案的怀疑。当我尝试不同的查询时,结果的顺序看起来像一个堆栈,结果按顺序推送,堆栈上的最后一项弹出进行递归,您链接的帖子证实 SQL Server 确实在内部以这种方式工作。

标签: sql-server common-table-expression recursive-query


【解决方案1】:

从一些测试来看,SQL 递归似乎深度首先从初始查询返回的最后一行开始。一旦到达MAXRECURSION,查询就会以错误终止(例如The statement terminated. The maximum recursion 2 has been exhausted before statement completion.)并返回它在错误之前到达的任何结果。您可以通过在插入语句中插入 2,1 而不是 1,2 或将 1,2,3 插入 @Number 表中来验证这一点。如果您将 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

通常,当使用递归时,您将 CTE 连接到自身或其他表,其中 where 语句中的某些条件或连接中的 on 条件将限制基于可用数据的递归(不仅仅是通过相同的元素)。例如(使用与您的问题相同的 @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

【讨论】:

  • 向你致敬,肖恩。你把解释解释为我发现的奇怪的排序。
【解决方案2】:

我把你的代码改了一下:

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

然后,我将结果与注释掉“其中迭代

我认为当 max loops 的错误发生时,或者当您选择切断最大递归时,它会以某种方式切断您在第 7-10 行中找到的后者结果。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-08-31
    • 2018-08-05
    • 1970-01-01
    • 2016-07-07
    • 2016-08-15
    • 1970-01-01
    • 2013-12-01
    相关资源
    最近更新 更多