如何为表值函数内的 CTE 设置 maxrecursion 选项
我在声明 TVF 内 CTE 的 maxrecursion 选项时遇到问题。
这是 CTE(一个简单的日历):
DECLARE @DEBUT DATE = '1/1/11', @FIN DATE = '1/10/11';
WITH CTE as(
SELECT @debut as jour
UNION ALL
SELECT DATEADD(day, 1, jour)
FROM CTE
WHERE DATEADD(day, 1, jour) <= @fin)
SELECT jour FROM CTE option (maxrecursion 365)
和 TVF:
CREATE FUNCTION [liste_jour]
(@debut date,@fin date)
RETURNS TABLE
AS
RETURN
(
WITH CTE as(
SELECT @debut as jour
UNION ALL
SELECT DATEADD(day, 1, jour)
FROM CTE
WHERE DATEADD(day, 1, jour) <= @fin)
SELECT jour FROM CTE
--option (maxrecursion 365)
)
上面的 TVF 在没有 maxrecursion 选项的情况下运行正常 但该选项存在语法错误。 解决办法是什么?
I'm facing a problem declaring the maxrecursion option for a CTE inside a TVF.
Here is the CTE (a simple calendar):
DECLARE @DEBUT DATE = '1/1/11', @FIN DATE = '1/10/11';
WITH CTE as(
SELECT @debut as jour
UNION ALL
SELECT DATEADD(day, 1, jour)
FROM CTE
WHERE DATEADD(day, 1, jour) <= @fin)
SELECT jour FROM CTE option (maxrecursion 365)
and the TVF:
CREATE FUNCTION [liste_jour]
(@debut date,@fin date)
RETURNS TABLE
AS
RETURN
(
WITH CTE as(
SELECT @debut as jour
UNION ALL
SELECT DATEADD(day, 1, jour)
FROM CTE
WHERE DATEADD(day, 1, jour) <= @fin)
SELECT jour FROM CTE
--option (maxrecursion 365)
)
The above TVF is running OK without the maxrecursion option
but there is a syntax error with the option.
What is the solution?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
从 这个 MSDN 论坛帖子我了解到
以及进一步
因此,在您的示例中,您必须在调用函数时指定
OPTION
:(稍后)
请注意,您无法通过使用第二个 TVF 来解决此问题上面的行 - 如果你尝试的话,你会得到同样的错误。 “[the] OPTION 子句只能在语句级别使用”,这是最终的(目前)。
From this MSDN forums thread I learn that
and further
So in your example, you must specify the
OPTION
when you call your function:(later)
Note that you can't work round this by having a second TVF that just does the above line - you get the same error, if you try. "[the]
OPTION
clause can be used only at the statement level", and that's final (for now).老线程,我知道,但我需要同样的东西,只是通过使用多语句 UDF 来处理它:
这可能存在效率问题,但在我的情况下我可以负担得起。
Old thread, I know, but I needed the same thing and just dealt with it by using a multi-statement UDF:
There are probably efficiency issues with this, but I can afford it in my case.
对 CTE 和笛卡尔积(交叉连接)进行一点创造性的使用将使您绕过 MAXRECURSION 100 的限制。最后一个限制为 4 条记录的 3 个 CTE 将为您带来 40,000 条记录,这将是适合 100 多年的数据。如果您期望@debut和@fin之间有更多差异,您可以调整
cte3
。A little creative use of CTEs and cartesian products (cross joins) will get you around the
MAXRECURSION
limit of 100. 3 CTEs with a limit of 4 records on the last one nets you 40,000 records, which will be good for more than 100 years worth of data. If you expect more difference between @debut and @fin, you can adjustcte3
.老问题但是......我只是想澄清为什么在内联表值函数中不允许使用
OPTION(MAXRECURSION x)
。这是因为当您在查询中使用它们时,iTVF 会内联。而且,众所周知,您不能将此选项放在查询最后的任何其他位置。这就是永远不可能将其放入 iTVF 中的原因(除非解析器和/或代数器在幕后做了一些魔法,我认为它不会很快实现)。 mTVF(多语句表值函数)是一个不同的故事,因为它们不会内联(并且速度太慢,以至于永远不应该在查询中使用它们;不过,在对变量的赋值中使用它们是可以的,但是再说一次——小心循环!)。Old issue but... I just wanted to clarify why
OPTION(MAXRECURSION x)
is not allowed in an in-line table-valued function. This is because iTVF's get inlined when you use them in a query. And, as we all know, you cannot put this option anywhere else save at the very end of the query. This is THE reason it will never be possible to put it inside an iTVF (unless the parser and/or algebrizer does some magic behind the scenes, which I don't think it will any time soon). mTVF's (multi-statement table-valued functions) is a different story because they don't get inlined (and are so slow that they should never be used in queries; it's OK to use them in an assignment to a variable, though, but then again---beware of loops!).处理此问题的另一种方法是将问题分解为一对 CTE,这两个 CTE 都不会达到 100 的递归限制。第一个 CTE 创建一个列表,其中包含该范围内每个月的开始日期。然后,第二个 CTE 填充每个月的所有天数。只要输入范围小于 100 个月,它就应该可以正常工作。如果需要大于 100 个月的输入范围,则可以通过在月份 CTE 之前添加年份的第三个 CTE 来扩展相同的想法。
Another way to handle this is to break up the problem into a pair of CTEs, neither of which hits the recursion limit of 100. The first CTE creates a list with the begin date for each month in the range. The second CTE then fills in all the days of each month. As long as the input range is fewer than 100 months, it should work fine. If an input range of greater than 100 months is required, the same idea could be expanded with a third CTE for years added ahead of the months CTE.
为您创建简单的示例:)
create simple sample for you :)