CTE 递归无限循环



我正在使用一个存储过程并在 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

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

接下来,您(希望)已经减少了实际查询。像"tableA"这样的通用名称会阻碍理解。

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

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

接下来,你添加混乱。您在 cte 声明中命名了列,但您的代码还包括某些(但不是全部 - 请参阅一致性注释)列的别名,这些列与 cte 的实际列名有很大不同。cte 的第二列是"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 <= 该值)?我认为这是您问题的根源。您不会从锚点计算或调整任何内容,因此递归部分只是不断选择和选择。没有逻辑来结束递归。

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

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

最新更新