使用 CTE 的多个日期范围

Multiple date ranges using CTE

我需要生成一个 table 半小时周期。我有以下有效的方法:

WITH ctePeriods AS
(
  SELECT  @gapStart HalfHourPeriod
  UNION ALL  
  SELECT  DATEADD(MINUTE, 30, HalfHourPeriod)
  FROM    ctePeriods  
  WHERE   HalfHourPeriod <  DATEADD(MINUTE, -30, @gapEnd)
)

这给了我@gapStart 和@gapEnd 之间范围的值。

但是我还有一个 table 范围需要生成:

create table #gaps(HHFrom datetime, HHTo datetime)

目前我正在使用它来获取上面使用的@gapStart 和@gapEnd 的值,方法是从#gaps 获取最小值和最大值。但这意味着我在 ctePeriods 中填写的行比我需要的多。

有什么方法可以在 ctePeriods 中使用#gaps 中的行,以便我只创建我需要的行?

我个人更喜欢使用 Tally Table 来处理这样的事情。您可以使用持久的 Tally Table,或者您即时创建一个(就像我在这里所做的那样):

CREATE TABLE #gaps (HHFrom datetime,
                    HHTo datetime);

INSERT INTO #gaps (HHFrom,
                   HHTo)
VALUES('20190101','20190103'),
      ('20190217','20190315'),
      ('20190708',GETDATE());
GO

WITH N AS(
    SELECT N
    FROM (VALUES(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL))N(N)),
Tally AS(
    SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) -1 AS I
    FROM N N1, N N2, N N3, N N4, N N5, N N6), --1000000 rows, feel free to increase/decrease per your own requirement
Dates AS(
    SELECT G.HHFrom,
           G.HHTo,
           DATEADD(MINUTE, 30*T.I, G.HHFrom) AS HH
    FROM #gaps G
         CROSS JOIN Tally T
    WHERE DATEADD(MINUTE, 30*T.I, G.HHFrom) <= G.HHTo)
SELECT *
FROM Dates D
ORDER BY D.HHFrom, D.HH;

GO

DROP TABLE #gaps;

与 rCTE 不同,这意味着对于大范围,如果您有超过 100 行(默认递归),则语句不会 "fall over",并且不像 rCTE 那样递归。