消除递归 CTE
Eliminate Recursive CTE
各位,
我希望有人可以帮助我获得相同的结果并消除这种递归 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
)
上述代码驻留在名为 fn_SplitPeriodIntoMonths 的 SQL 服务器中的 Table 值函数中。
可以调用函数
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
如您所见,结果是按月细分的期间。相当酷。然后可以通过多种方式使用它。但是,如果用具有 "too" 多行的 select 来调用它,我们就会达到 MAXRECUSION LIMIT。
非常感谢任何帮助。
祝一切顺利,
乔治
/****** 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
各位,
我希望有人可以帮助我获得相同的结果并消除这种递归 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
)
上述代码驻留在名为 fn_SplitPeriodIntoMonths 的 SQL 服务器中的 Table 值函数中。
可以调用函数
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
如您所见,结果是按月细分的期间。相当酷。然后可以通过多种方式使用它。但是,如果用具有 "too" 多行的 select 来调用它,我们就会达到 MAXRECUSION LIMIT。
非常感谢任何帮助。
祝一切顺利,
乔治
/****** 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