首页 > 解决方案 > 如何停止 CTE 中的递归?

问题描述

我有一个如下所示的数据库表:

ID                                   | PredecessorID                        | Data
-------------------------------------|--------------------------------------|-----------------
43b1e103-d8c6-40f9-b031-e5d9ef18a739 | null                                 | ...
55f6951b-5ed3-46c8-9ad5-64e496cb521a | 43b1e103-d8c6-40f9-b031-e5d9ef18a739 | ...
3eaa0889-31a6-449d-a499-e4beb9e4cad1 | 55f6951b-5ed3-46c8-9ad5-64e496cb521a | ...

我知道我可以使用(递归)公用表表达式(CTE)来获取我的数据的排序列表:

WITH cte (ID, Data)
AS
(
  -- base case
  SELECT x.ID, x.Data
  FROM MyTable AS x
  WHERE x.PredecessorID IS NULL

  UNION ALL

  -- other cases
  SELECT x.ID, x.Data
  FROM MyTable as x
  INNER JOIN cte
    ON x.PredecessorID = cte.ID
)
SELECT * FROM cte

虽然这可行,但如果我想获取整个表,我想知道如何只获取表的一部分,例如从 IDx到 ID之间的所有内容y

获得正确的下限很容易(我假设):只需WHERE将基本案例的标准更改为我想要开始的 ID:

  -- base case
  SELECT x.ID, x.Data
  FROM MyTable AS x
  WHERE x.PredecessorID='...'

但是上限呢?一旦达到带有 ID 的记录,我如何告诉 CTE 停止递归y

标签: sqlrecursioncommon-table-expression

解决方案


由于您在此处进行迭代并且在递归术语中获得了 cte 的最后一个 id,因此您可以过滤掉最后一次迭代命中“y”的结果

WITH cte (ID, Data)
AS
(
  -- base case
  SELECT x.ID, x.Data
  FROM MyTable AS x
  WHERE x.PredecessorID IS NULL

  UNION ALL

  -- other cases
  SELECT x.ID, x.Data
  FROM MyTable as x
  INNER JOIN cte
    ON x.PredecessorID = cte.ID
  WHERE cte.id <> 'y'
)
SELECT * FROM cte;

请注意,如果您的xid 有许多分支,其中一些不会导致“y”,那么这些分支将继续迭代,直到它们达到自然结束。只有通向的分支y会在这里提前停止。


推荐阅读