在 WHERE 子句中更改运算符时,简单的递归 CTE 会爆炸

jdi*_*ids 1 sql-server t-sql sql-server-2012

正如标题所述,我有一个递归 CTE,当我更改 WHERE 子句中的运算符时,即使只有两行数据,它也会爆炸。

CREATE TABLE #Recursion
(Parent varchar(10), Child varchar(10), TopDate datetime)


INSERT INTO #Recursion (Parent, Child, TopDate)
VALUES
('00003137', '00003137', '2018-08-31'),
('04536347', '00003137', '2017-02-28'),
('05458040', '05458040', '9999-12-31'),
('00269705',' 05458040',' 9999-12-31')

;WITH 
Parent AS
  ( SELECT parent
     , child
     , 1 as sort
     , TopDate
 FROM #Recursion 
WHERE parent = child
 UNION ALL
   SELECT s.parent
        , d.child
        , d.sort + 1
        , s.TopDate
 FROM Parent as d
 JOIN #Recursion s
   ON s.child= d.parent
WHERE s.TopDate < d.TopDate
)

  SELECT parent
       , child
       , sort
    FROM Parent 
ORDER BY parent, sort desc
OPTION (maxrecursion 0);

DROP TABLE #Recursion
Run Code Online (Sandbox Code Playgroud)

如果我保留 where 子句,它会起作用

WHERE s.TopDate < d.TopDate
Run Code Online (Sandbox Code Playgroud)

一旦我将其更改为这个,它就会爆炸并且不会完成

WHERE s.TopDate <= d.TopDate
Run Code Online (Sandbox Code Playgroud)

如果日期小于或等于,我确实需要运行一些测试。为什么这行不通,即使只有两行数据?

这是一些示例数据。请注意日期字段如何相同

parent      child       sort    TopDate
00003137    04536347    2       2017-02-28
00003137    00003137    1       2018-08-31
00269705    00269705    2       9999-12-31      
00269705    05458040    1       9999-12-31
Run Code Online (Sandbox Code Playgroud)

除了具有相同 TopDates 的数据,我可以让它处理所有数据

Dav*_*oft 5

如果您将根节点建模为具有 parent=child,则必须将它们从递归子句中排除,否则您将获得无限循环。您s.TopDate < d.TopDate目前是查询中唯一防止无限循环的东西。

EG,如果更改<<=查询将进入一个无限循环。请注意,这(maxrecursion 0)可能不是一个好主意。

drop table if exists #Recursion
go
create table #Recursion(parent int, child int, topdate datetime)
go
insert into #Recursion(parent,child,topdate) values (1,1,getdate());

;WITH 
Parent AS
  ( SELECT parent
         , child
         , 1 as [order]
         , TopDate
     FROM #Recursion 
    WHERE parent = child
 UNION ALL
   SELECT s.parent
        , d.child
        , d.[order] + 1
        , s.TopDate
     FROM Parent as d
     JOIN #Recursion s
       ON s.child = d.parent
    WHERE s.TopDate < d.TopDate
)

  SELECT parent
       , child
       , [order]
    FROM Parent 
ORDER BY parent, [order] desc
OPTION (maxrecursion 0);
Run Code Online (Sandbox Code Playgroud)

ON s.child = d.parent
Run Code Online (Sandbox Code Playgroud)

应该是

ON d.child = s.parent
Run Code Online (Sandbox Code Playgroud)

由于您似乎是从根节点开始,因此您需要通过 UNION ALL 行向下递归这些行parent是前一次迭代的child.