【问题标题】:Stopping recursive CTE with a guard使用警卫停止递归 CTE
【发布时间】:2020-09-10 10:47:41
【问题描述】:

我有以下从源到目标的分层数据,我想在出现对现有源的引用时停止

create table #temp (source int, destination int);
insert into #temp values (1,3), (3,7), (7,9), (9,1);

WITH cte (Source, Destination, Level, Sources)
AS 
(
    SELECT Source, Destination, 0 AS Level, CAST(Source AS VARCHAR(MAX)) + ',' AS Sources
    FROM #temp 
    WHERE [Source] = 1

    UNION ALL

    SELECT t.[Source], t.Destination, cte.[Level] + 1, cte.Sources + CAST(t.Source AS VARCHAR(MAX)) + ','
    FROM #temp t        
        INNER JOIN cte ON cte.Destination = t.[Source] AND (CAST(t.Destination AS VARCHAR(MAX)) + ',' NOT LIKE '%' + cte.Sources + '%')
)
select * from cte

drop table #temp;

但是,在运行此程序时,我仍然会遇到最大递归错误。我应该如何正确编写保护条款?我想要的是前 3 个结果。

【问题讨论】:

  • CTE 第二部分中的where 子句通常可以解决问题。 where cte.[Level] < 2 之类的东西(应该给出 3 个结果:级别 0、1 和 2)。

标签: sql-server common-table-expression infinite-loop


【解决方案1】:

在 CTE 的递归部分添加 where 子句。

create table #temp (source int, destination int);
insert into #temp values (1,3), (3,7), (7,9), (9,1);

WITH cte (Source, Destination, Level, Sources)
AS 
(
    SELECT Source, Destination, 0 AS Level, CAST(Source AS VARCHAR(MAX)) + ',' AS Sources
    FROM #temp 
    WHERE [Source] = 1

    UNION ALL

    SELECT t.[Source], t.Destination, cte.[Level] + 1, cte.Sources + CAST(t.Source AS VARCHAR(MAX)) + ','
    FROM #temp t        
        INNER JOIN cte ON cte.Destination = t.[Source] AND (CAST(t.Destination AS VARCHAR(MAX)) + ',' NOT LIKE '%' + cte.Sources + '%')
    where cte.Level < 2 -- stop after 3 levels (0,1,2)
)
select * from cte

drop table #temp;

Fiddle

【讨论】:

    【解决方案2】:

    这里,在 CTE 的递归成员中:

    INNER JOIN cte 
        ON  cte.Destination = t.[Source] 
        AND (CAST(t.Destination AS VARCHAR(MAX)) + ',' NOT LIKE '%' + cte.Sources + '%')
    

    您的 LIKE 操作数错误。而是:

    INNER JOIN cte 
        ON cte.Destination = t.[Source] 
        AND cte.Sources NOT LIKE CONCAT('%', t.Destination, '%')
    

    即:目的地应该属于已经访问过的来源列表。请注意,使用CONCAT() 会强制将数字转换为字符串,从而缩短表达式。

    Demo on DB Fiddle

    【讨论】:

      猜你喜欢
      • 2019-03-10
      • 1970-01-01
      • 1970-01-01
      • 2018-02-03
      • 2014-01-13
      • 2014-08-11
      • 1970-01-01
      • 1970-01-01
      • 2016-10-19
      相关资源
      最近更新 更多