Table 具有递归 CTE 的值函数
Table Valued Function with Recursive CTE
只是为了好玩,我正在尝试编写一个 table 值函数来生成 table 日期。出于测试目的,我硬编码了应该在变量中传递的值。
这本身有效:
WITH cte AS (
SELECT cast('2021-10-01' AS date) AS date
UNION ALL
SELECT dateadd(day,1,date) FROM cte WHERE date<current_timestamp
)
SELECT * FROM cte OPTION(maxrecursion 0);
注意最后的OPTION
。
作为一个函数,除非我删除末尾的 OPTION
子句,否则它不会工作:
CREATE FUNCTION dates(@start date, @rows INT) RETURNS TABLE AS
RETURN
WITH cte AS (
SELECT cast('2021-10-01' AS date) AS date
UNION ALL
SELECT dateadd(day,1,date) FROM cte WHERE date<current_timestamp
)
SELECT * FROM cte -- OPTION(maxrecursion 0)
;
测试数据还行,如果我给它年初的日期肯定会失败,因为它涉及100多次递归。
是否有正确的语法,或者这是另一个需要解决方法的 Microsoft Quirk?
我认为这可能就是答案。
@GarethD 在回答另一个问题时说:
If you think of a view more as a stored subquery than a stored query … and remember that its definition is expanded out into the main query …
(Incorrect Syntax Near Keyword 'OPTION' in CTE Statement).
如果是这样,视图就不能包含任何不能包含在子查询中的内容。这包括 ORDER BY
子句和 OPTION
.
等提示
我还没有确定,但我猜想 Table 值函数也是如此。如果是这样,答案是否定的,没有办法包含 OPTION
子句。
请注意,其他 DBMS 在子查询中可以包含的内容方面更为宽松,因此我不认为它们具有相同的限制。
解决方案是使用多语句Table值函数:
DROP FUNCTION IF EXISTS dates;
GO
CREATE FUNCTION dates(@start date, @end date) RETURNS @dates TABLE(date date) AS
BEGIN
WITH cte AS (
SELECT @start AS date
UNION ALL
SELECT dateadd(day,1,date) FROM cte WHERE date<@end
)
INSERT INTO @dates(date)
SELECT date FROM cte OPTION(MAXRECURSION 0)
RETURN;
END;
GO
SELECT * FROM dates('2020-01-01','2021-01-01');
Inline Table Value Functions 是字面上的内联,OPTION
等子句只能出现在 SQL 语句的末尾,不一定在语句的末尾内联函数。
另一方面,多语句 Table 值函数是真正独立的,因此 OPTION
子句在那里是可以的。
只是为了好玩,我正在尝试编写一个 table 值函数来生成 table 日期。出于测试目的,我硬编码了应该在变量中传递的值。
这本身有效:
WITH cte AS (
SELECT cast('2021-10-01' AS date) AS date
UNION ALL
SELECT dateadd(day,1,date) FROM cte WHERE date<current_timestamp
)
SELECT * FROM cte OPTION(maxrecursion 0);
注意最后的OPTION
。
作为一个函数,除非我删除末尾的 OPTION
子句,否则它不会工作:
CREATE FUNCTION dates(@start date, @rows INT) RETURNS TABLE AS
RETURN
WITH cte AS (
SELECT cast('2021-10-01' AS date) AS date
UNION ALL
SELECT dateadd(day,1,date) FROM cte WHERE date<current_timestamp
)
SELECT * FROM cte -- OPTION(maxrecursion 0)
;
测试数据还行,如果我给它年初的日期肯定会失败,因为它涉及100多次递归。
是否有正确的语法,或者这是另一个需要解决方法的 Microsoft Quirk?
我认为这可能就是答案。
@GarethD 在回答另一个问题时说:
If you think of a view more as a stored subquery than a stored query … and remember that its definition is expanded out into the main query …
(Incorrect Syntax Near Keyword 'OPTION' in CTE Statement).
如果是这样,视图就不能包含任何不能包含在子查询中的内容。这包括 ORDER BY
子句和 OPTION
.
我还没有确定,但我猜想 Table 值函数也是如此。如果是这样,答案是否定的,没有办法包含 OPTION
子句。
请注意,其他 DBMS 在子查询中可以包含的内容方面更为宽松,因此我不认为它们具有相同的限制。
解决方案是使用多语句Table值函数:
DROP FUNCTION IF EXISTS dates;
GO
CREATE FUNCTION dates(@start date, @end date) RETURNS @dates TABLE(date date) AS
BEGIN
WITH cte AS (
SELECT @start AS date
UNION ALL
SELECT dateadd(day,1,date) FROM cte WHERE date<@end
)
INSERT INTO @dates(date)
SELECT date FROM cte OPTION(MAXRECURSION 0)
RETURN;
END;
GO
SELECT * FROM dates('2020-01-01','2021-01-01');
Inline Table Value Functions 是字面上的内联,OPTION
等子句只能出现在 SQL 语句的末尾,不一定在语句的末尾内联函数。
另一方面,多语句 Table 值函数是真正独立的,因此 OPTION
子句在那里是可以的。