我正在使用存储过程并在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
答案 0 :(得分:1)
首先,让我们尝试添加一些最佳实践。使用适当的表别名限定所有列。仅执行其中一些操作就会前后不一致,并且样式不一致很难阅读并且容易出错。
接下来,您(希望)简化了您的实际查询。诸如“ tableA”之类的通用名称妨碍理解。
下一步-您的第一种情况表达似乎非常可疑。您有一个分支返回tb.id,其他分支返回似乎是日期(或日期时间)的东西。不幸的是,您可以将int转换为日期时间。可能没有任何意义,也不会产生错误。所以-这有意义吗?
下一步-您在日期时间边界上犯了一个常见错误。根据您的数据,您可能永远不会知道这一点。但是没有理由期望这样做,并且有充分的理由编写您的逻辑以免发生任何可能性。 Tibor详细讨论了here。较短的版本-您的上限应始终是唯一的,以支持数据类型的所有可能的时间值。 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'
考虑一下您写的内容。结束日期是否不总是介于结束日期和2010年12月31日之间(只要结束日期<=该值)?我认为这是您问题的根源。您不需要计算或调整锚点的内容,因此递归部分只是不断地进行选择和选择。没有结束递归的逻辑。
下一个问题显然是“现在要解决”。如果不知道您的模式,它代表什么以及您的目标,这是无法说的。在这里使用递归并不明显。
答案 1 :(得分:0)
如果数据处于记录之间的层次结构为循环的结构中,则递归进行到无限会导致SQL问题。您将看到SQL进程使用的资源正在急剧增加。 如果您使用的MAXRECURSION的值不同于0(零,则SQL可以无限制地继续递归),您将能够限制递归。 对于循环或相互引用的数据,您可以使用此MAXRECURSION参数