SQL Server 2008 - 枚举多个日期范围

时间:2014-02-11 18:13:03

标签: sql sql-server-2008

如何在SQL Server 2008中枚举多个日期范围?如果我的表包含单个记录

,我知道如何做到这一点
StartDate   EndDate
2014-01-01  2014-01-03

;WITH DateRange
AS (
    SELECT @StartDate AS [Date]
    UNION ALL

    SELECT DATEADD(d, 1, [Date])
    FROM DateRange
    WHERE [Date] < @EndDate
    )
SELECT * FROM DateRange

输出

2014-01-01, 2014-01-02, 2014-01-03

但是如果我的表包含多个记录,我会失去如何做到这一点。我可以在游标中使用上述逻辑,但想要知道是否存在基于集合的解决方案。

StartDate    EndDate
2014-01-01   2014-01-03
2014-01-05   2014-01-06

期望的输出:

2014-01-01, 2014-01-02, 2014-01-03, 2014-01-05, 2014-01-06

3 个答案:

答案 0 :(得分:0)

您可以先获取最短和最长日期,如下所示:

SELECT @startDate = MIN(StartDate), @endDate = MAX(EndDate)
FROM YourTable
WHERE ...

然后将这些变量传递到日期范围枚举器。

编辑... 哎呀,我错过了一个重要的要求。请参阅接受的答案。

答案 1 :(得分:0)

嗯,让我们看看。将范围定义为表格。然后生成从第一个到最后一个日期的全部日期。最后,选择范围内的日期:

with dateranges as (
      select cast('2014-01-01' as date) as StartDate, cast('2014-01-03' as date) as EndDate union all
      select '2014-01-05', '2014-01-06'
     ),
     _dates as (
      SELECT min(StartDate) AS [Date], max(EndDate) as enddate
      FROM dateranges
      UNION ALL
      SELECT DATEADD(d, 1, [Date]), enddate
      FROM _dates
      WHERE [Date] < enddate
     ),
     dates as (
      select [date]
      from _dates d
      where exists (select 1 from dateranges dr where d.[date] >= dr.startdate and d.[date] <= dr.enddate)
    )
select *
from dates 
. . . 

您可以看到此作品here

答案 2 :(得分:0)

正如GordonLinoff所说,你应该:

  1. 将范围存储在表格中
  2. 生成包含范围的日期范围
  3. 仅过滤到属于
  4. 范围内的日期

    以下查询构建了一组数字,然后使用它来快速生成每个范围内的所有日期。

    -- Create a table of digits (0-9)
    DECLARE @Digits TABLE (digit INT NOT NULL PRIMARY KEY);
    INSERT INTO @Digits(digit)
    VALUES (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
    WITH
    -- Store our ranges in a common table expression
    CTE_DateRanges(StartDate, EndDate)  AS  (
        SELECT  '2014-01-01', '2014-01-03'
        UNION ALL
        SELECT  '2014-01-05', '2014-01-06'
    )
    
    SELECT  DATEADD(DAY, NUMBERS.num, RANGES.StartDate) AS Date
    FROM
    (
        -- Create the list of all 3-digit numbers (0-999)
        SELECT D3.digit * 100 + D2.digit * 10 + D1.digit AS num
        FROM @Digits AS D1
        CROSS JOIN @Digits AS D2
        CROSS JOIN @Digits AS D3
        -- Add more CROSS JOINs to @Digits if your ranges span more than 999 days
    )   NUMBERS
    -- Join to our ranges table to generate the dates and filter them
    -- down to those that fall within a range
    INNER JOIN  CTE_DateRanges  RANGES
        ON  DATEADD(DAY, NUMBERS.num, RANGES.StartDate) <= RANGES.EndDate
    ORDER   BY
            Date
    

    通过将我们的号码列表与我们的日期范围相结合来创建日期,使用该号码作为添加到范围StartDate的天数。然后,我们过滤掉任何结果,其中给定范围的生成日期超出该范围EndDate。由于我们在StartDate添加非负天数以生成日期,因此我们知道我们的日期将始终大于或等于范围的StartDate ,因此我们不需要在StartDate子句中包含WHERE

    此查询将返回DATETIME个值。如果您需要DATE值,而不是DATETIME值,则只需将值转换为SELECT子句。

    对于数字表,信用转到Itzik Ben-Gan