【问题标题】:CTE recursion infinite loopCTE递归无限循环
【发布时间】:2019-03-28 00:16:04
【问题描述】:

我正在使用存储过程并在 SQL Server 中使用 CTE,我试图从 2 个表中获取一些数据,但是当执行到 CTE 查询时,它会进入无限循环并且永远不会结束,有没有办法防止这种无限循环?

这是我创建的查询:

WITH tableName(Id, enddate, statusDte, closeId, shceDte, calcDte, closeEndDte, ParentId, LastClose, lasCloseDte, closeClass,addSe,twon,code)
AS
(
    SELECT 
        tba.Id,
        CASE WHEN tb.ParentId IS NOT NULL 
                THEN tb.Id
             WHEN tb.statusDte IN (1,2,3) 
                THEN  tb.calcDte ELSE tb.shceDte 
                END ForecastDueDate, 
        statusDte, closeId, shceDte, calcDte, 
        CASE WHEN tb.ParentId IS NULL 
                THEN closeEndDte ELSE NULL END, tb.ParentId, 0, 
        CASE WHEN tb.ParentId IS NOT NULL 
                THEN statusDte
             WHEN tb.statusDte = 5
             AND (tb.calcDte BETWEEN '1/1/2020 12:00:00 AM' AND '12/31/2020 11:59:59 PM' 
             OR tb.closeEndDte BETWEEN '1/1/2020 12:00:00 AM' AND '12/31/2020 11:59:59 PM') 
                THEN ams.GetPreviousNthFullAuditDate(tb.Id, tb.AuditID, 2)  ELSE a.statusDate END as lastDate,
        a.closeClass, tba.addSe,tba.town,tba.code
    FROM 
        tableA tba 
    INNER JOIN 
        tableB tb ON tb.Id = tba.Id 
    WHERE 
        statusDte NOT IN (3,4) AND tba.IsAtve = 1

    UNION ALL

    SELECT 
        Id, enddate, 
        statusDte, statusDte, shceDte, calcDte, closeEndDte, ParentId,
        0, lasCloseDte, closeClass,addSe,twon,code
    FROM 
        tableName
    WHERE 
        enddate BETWEEN enddate AND '12/31/2020 11:59:59 PM'
)
SELECT * 
FROM tableName
OPTION (maxrecursion 0)

预期结果

Id                  enddate          statusDte      closeId         shceDte                 calcDte             closeEndDte                 parentId          lastClose       lastCloseDte         closeClass  addSe                               town                      code
----------- ----------------------- ------------- ----------- ----------------------- ----------------------- ----------------------- ----------------------- ----------- ----------------------- ----------- --------------------------------- ---------------------- --------------------------------------------------
133           2011-04-04 00:00:00.000 22            14453       NULL                    2011-04-04 00:00:00.000 2099-12-31 00:00:00.000 NULL                    0           NULL                    1           4707 EXECUTIVE DRIVE  ''             SAN DIEGO               123
56           2018-12-07 13:00:00.000 22            52354       NULL                    2018-12-07 13:00:00.000 2019-12-07 00:00:00.000 NULL                    0           NULL                    1           75 STATE ST FL 24  ''                BOSTON                   345
12          2021-02-05 17:00:00.000 22            75751       NULL                    2021-02-05 17:00:00.000 NULL                    NULL                    0           NULL                    1           1450 FRAZEE RD STE 308  ''           SAN DIEGO                 678
334          2019-03-07 16:30:00.000 15            66707       2019-03-07 16:30:00.000 2019-03-23 21:00:00.000 NULL                    NULL                    0           2019-03-07 16:30:00.000 1           42690 RIO NEDO, STE E  ''            TEMECULA                 91011
33          2020-01-10 17:00:00.000 22            65568       NULL                    2020-01-10 17:00:00.000 NULL                    NULL                    0           2018-01-10 17:00:00.000 1           2518 UNICORNIO ST.  ''               CARLSBAD                  136
55          2020-04-16 20:00:00.000 22            67812       NULL                    2020-04-16 20:00:00.000 NULL                    NULL                    0           2018-04-17 20:00:00.000 1           4534 OSPREY STREET  ''               SAN DIEGO                 653
66          2020-02-21 17:00:00.000 22            75956       NULL                    2020-02-21 17:00:00.000 NULL                    NULL                    0           2019-02-21 17:00:00.000 1           3511 CAMINO DEL RIO S, STE 305  ''   SAN DIEGO                 0484
094          2021-02-20 21:00:00.000 22            75629       NULL                    2021-02-20 21:00:00.000 NULL                    NULL                    0           NULL                    1           29349 EAGLE DR  ''                   MURRIETA                 345

【问题讨论】:

  • 递归部分应该以某种方式与锚部分相关。
  • 当然@D-Shih 我用信息更新了问题
  • This answer 演示了一种在检测到循环时终止递归的方法。一种方便的调试技术是向锚添加一列,例如0 as Depth,并在查询的递归部分增加它@9​​87654325@,然后在递归where 子句中使用它来限制递归深度,例如where Depth <= 2 and ...,然后检查结果。您应该能够发现问题,但可能需要增加深度限制,直到问题变得清晰。

标签: sql sql-server tsql


【解决方案1】:

首先,让我们尝试添加一些最佳实践。使用适当的表别名限定所有列。只做其中一些是不一致的,不一致的样式难以阅读并且容易出错。

接下来,您(希望)简化了您的实际查询。像“tableA”这样的通用名称会妨碍理解。

接下来 - 您的第一个 case 表达式似乎非常可疑。您有一个分支返回 tb.id,而其他分支返回似乎是日期(或日期时间)的内容。不幸的是,您可以将 int 转换为日期时间。可能没有任何意义,也不会产生错误。那么 - 这有意义吗?

接下来 - 您在日期时间界限方面犯了一个常见错误。根据您的数据,您可能永远不会知道这一点。但是没有理由期望这一点,并且有充分的理由编写您的逻辑以避免任何可能性。 Tibor 非常详细地讨论了here。较短的版本 - 您的上限应该始终是唯一的,以支持您的数据类型的所有可能的时间值。 23:59:59 将忽略任何非零毫秒的时间值。并使用不依赖于语言或连接设置的文字格式。

接下来,您添加混乱。您在 cte 声明中命名了列,但您的代码还包含一些(但不是全部 - 请参阅一致性注释)列的别名,这些列与 cte 的实际列名有很大不同。 cte 的第 2 列是“enddate”,锚查询使用别名“ForecastDueDate”

接下来,你有这个:tb.statusDte = 5。名字暗示日期;字面意思是不同的东西。您还有其他以“Dte”结尾的列显然是日期,但不是这一列?危险,危险!

接下来,您参考列“a.closeClass”和“a.statusDate”。没有名为“a”的表或别名。

最后,你有:

WHERE enddate BETWEEN enddate AND '12/31/2020 11:59:59 PM'

想想你写了什么。 enddate 是否总是在 enddate 和 2010 年 12 月 31 日之间(只要 enddate

下一个问题显然是“现在修复它”。如果不知道您的架构、它代表什么以及您的目标,这是不可能说的。这里递归的使用并不明显。

【讨论】:

  • 感谢您的评论,是的,代码令人困惑,实际上这是遗留代码,我只是想找到解决方案,我对 cte 和递归查询进行了大量研究,但没有有帮助,但你是对的,这段代码根本没有好的做法。但是感谢您的建议,我感谢您的每一条评论或帮助! :)
  • 有些不匹配。您说这是遗留代码,这意味着您正在将其移植/迁移到“新”的东西。这意味着您已经添加了递归,否则它在遗留系统中也不起作用。再说一遍 - 您需要准确了解这段代码在遗留系统中的作用以及迁移它的目标(也许“增强”是一个更好的术语)。
【解决方案2】:

如果数据位于记录之间的层次结构是循环的结构中,则递归将无限循环,从而导致 SQL 出现问题。您将看到 SQL 进程使用的资源正在急剧增加。 如果您使用 MAXRECURSION 的值不同于 0(零允许 SQL 继续无限制地递归),您将能够限制递归。 对于循环或相互引用的数据,您可以使用 MAXRECURSION 参数

【讨论】:

  • 感谢@Eralper!我尝试使用其他值,例如 1,2 和 100,这些值会停止无限循环,但在应用程序中,发生这种情况时会出现错误,因为查询抛出并警告消息说 The statement terminated. The maximum recursion 100 has been exhausted before statement completion. 所以应用程序中的数据集未填写并显示错误。
猜你喜欢
  • 2020-02-08
  • 1970-01-01
  • 2023-04-06
  • 2016-09-28
  • 2016-10-06
  • 2021-11-04
  • 1970-01-01
  • 2014-10-13
  • 1970-01-01
相关资源
最近更新 更多