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