消除递归CTE

时间:2018-07-24 15:59:04

标签: sql-server user-defined-functions common-table-expression recursive-query

所有人

我希望外面有人可以帮助我获得相同的结果,并消除这种递归CTE。从原则上讲,这听起来很简单,但是我已经为此工作了至少两天,什么也没想出来。最后一件事,我知道OPTION(MAXRECURSION 0)选项。这对我们来说不是可行的选择。我们处于生产环境中,不希望对数据库进行爬网。如果可能的话,我们希望摆脱递归CTE。

WITH cte AS
(
    SELECT DATEADD(month, DATEDIFF(month, 0, @StartDate), 0) AS StartOfMonth, 
               DATEADD(s, 0, DATEADD(mm, DATEDIFF(m, 0, @StartDate) + 1, 0)) AS EndOfMonth
        UNION ALL
        SELECT DATEADD(month, 1, StartOfMonth) AS StartOfMonth, 
               DATEADD(s, 0, DATEADD(mm, DATEDIFF(m, 0, DATEADD(month, 1, StartOfMonth)) + 1, 0)) AS EndOfMonth  
        FROM   cte
        WHERE  DATEADD(month, 1, StartOfMonth) <= @EndDate
)

上面的代码位于SQL Server中名为fn_SplitPeriodIntoMonths的表值函数中。

一个可以调用该函数的

SELECT * FROM fn_SplitPeriodIntoMonths('2018-01-01','2018-09-01') 

然后结果就是这个

StartOfMonth                   EndOfMonth
2018-01-01 00:00:00.000        2018-02-01 00:00:00.000
2018-02-01 00:00:00.000        2018-03-01 00:00:00.000
2018-03-01 00:00:00.000        2018-04-01 00:00:00.000
2018-04-01 00:00:00.000        2018-05-01 00:00:00.000
2018-05-01 00:00:00.000        2018-06-01 00:00:00.000
2018-06-01 00:00:00.000        2018-07-01 00:00:00.000
2018-07-01 00:00:00.000        2018-08-01 00:00:00.000
2018-08-01 00:00:00.000        2018-09-01 00:00:00.000
2018-09-01 00:00:00.000        2018-10-01 00:00:00.000

您可以看到结果是按月细分的期间。挺酷的。然后,人们可以以多种方式使用它。但是,如果使用行太多的选择来调用它,我们将达到MAXRECUSION LIMIT。

任何帮助将不胜感激。

祝一切顺利,

乔治

1 个答案:

答案 0 :(得分:2)

/****** Object:  UserDefinedFunction [dbo].[fn_SplitPeriodIntoMonths]    Script Date: 24/07/2018 17:29:05 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Author:      Andy Deighton
-- Create date: 24/07/2018
-- Description: Return a date table
-- =============================================
ALTER FUNCTION [dbo].[fn_SplitPeriodIntoMonths]
(   
    -- Add the parameters for the function here
    @START DATE,
    @END DATE
)
RETURNS TABLE 
AS
RETURN 
(

    SELECT AM.StartOfMonth, EOMONTH(AM.StartOfMonth) EndOfMonth FROM
    (
    SELECT datefromparts(100 * (c.century - 1) + 10 * (d.decade -1) + y.[year],M.[month],1) StartOfMonth                   
                                  FROM 
                                  (SELECT 20 century UNION SELECT 21) C
                                    CROSS JOIN 
                                    (SELECT decade FROM 
                                                (VALUES (1), (2), (3), (4), (5), (6),(7),(8),(9), (10)) 
                                                    X(decade)) D
                                    CROSS JOIN 
                                    (SELECT [year] FROM 
                                                (VALUES (0), (1), (2), (3), (4), (5),(6),(7),(8), (9)) 
                                                    X([year])) Y
                                    CROSS JOIN 
                                    (SELECT [month] FROM 
                                                (VALUES (1), (2), (3), (4), (5),(6),(7),(8), (9), (10), (11),(12)) 
                                                    X([month])) M
    ) AM WHERE AM.StartOfMonth BETWEEN @START AND @END




)

示例通话

    select * from dbo.fn_SplitPeriodIntoMonths('19660101','20450101') order by startofmonth