如何在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
答案 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所说,你应该:
以下查询构建了一组数字,然后使用它来快速生成每个范围内的所有日期。
-- 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。