【问题标题】:Get all dates in date range in SQL Server在 SQL Server 中获取日期范围内的所有日期
【发布时间】:2012-02-26 18:12:59
【问题描述】:

我从一个被问到的 StackOverflow 问题中得到了这个例子,但我无法根据我的需要让它工作。

WITH DateTable
AS
(
    SELECT CAST('20110101' as Date) AS [DATE]
    UNION ALL
    SELECT DATEADD(dd, 1, [DATE]) FROM DateTable 
    WHERE DATEADD(dd, 1, [DATE]) < cast('20110131' as Date)
)
SELECT dt.[DATE] FROM [DateTable] dt

输入-

ID |   FromDate  | ToDate
=============================
1  |  2011-11-10 | 2011-11-12
2  |  2011-12-12 | 2011-12-14

输出 -

SN |   Dates     | 
==================
1  |  2011-11-10 | 
2  |  2011-11-11 | 
3  |  2011-11-12 | 
4  |  2011-12-12 | 
5  |  2011-12-13 | 
6  |  2011-12-14 |

查看此代码适用于静态日期。但就我而言,我有一个包含三列Id, FromDate, ToDate 的表。现在我想将每一行中的每个范围转换为单独的日期。

如果范围来自表,并且显然必须为范围表中的每一行运行此查询,我无法让上面的示例工作,这是另一个令人困惑的挑战。

请帮忙。

【问题讨论】:

  • 您是否尝试获取每个 Id 的 FromDate 和 ToDate 之间的所有有效日期?我不确定你想要完成什么。
  • 请注意,最大递归默认为 100

标签: sql sql-server-2005 tsql datetime date-range


【解决方案1】:

在数字表的帮助下。

declare @T table
(
  ID int identity primary key,
  FromDate date,
  ToDate date
)

insert into @T values
('2011-11-10', '2011-11-12'),
('2011-12-12', '2011-12-14')

select row_number() over(order by D.Dates) as SN,
       D.Dates
from @T as T
  inner join master..spt_values as N
    on N.number between 0 and datediff(day, T.FromDate, T.ToDate)
    cross apply (select dateadd(day, N.number, T.FromDate)) as D(Dates)
where N.type ='P'

试试SE Data

【讨论】:

  • @JCooper 不。数字表以0 开头,请查看链接。它将给出以FromDate 开头并以EndDate 结尾的预期输出。
  • 我使用链接运行查询,您的结果从 11-09 - 11-11 而不是 11-10 到 11-12,除了替代方法的 +1
  • @JCooper - 这确实很奇怪。当我单击链接时,它显示 10 到 12 和 12 到 14。我想知道为什么它不同。
  • @JCooper - 你在哪个时区?我在 GMT+1,日期有时间部分,不应该有。如果您在 GMT-x 中,它将解释为什么您会看到日期 -1。 SE-Data 发生了一些奇怪的事情。
  • @SohamDasgupta - spt_values 的编号从 0 到 2047。如果您不希望有一个日期范围超过 2047 天,那应该没问题。您还可以创建自己的数字表。在不止一次的场合下会很好。确保第一个数字是 0。请查看 Jeff Moden 在 SQLServerCentral.com 上的 this article
【解决方案2】:
create table Dates (Id int, FromDate date, ToDate date)
insert into Dates values (1, '2011-11-10', '2011-11-12')
insert into Dates values (2, '2011-12-12', '2011-12-14')

with DateTable as
(
    select FromDate as Dt, ToDate
    from Dates
    union all
    select DATEADD(D, 1, Dt), ToDate
    from DateTable
    where DATEADD(D, 1, Dt) <= ToDate
)
select ROW_NUMBER() over (order by Dt) as SN, Dt as Dates
from DateTable
order by Dt

【讨论】:

    【解决方案3】:

    这个怎么样?

    --DROP TABLE #Test
    CREATE TABLE #Test(ID int, FromDate datetime, ToDate datetime)
    INSERT INTO  #Test VALUES (1, '2011-11-10', '2011-11-12')
    INSERT INTO  #Test VALUES (2, '2011-12-12', '2011-12-14')
    
    ;
    WITH DateTable
    AS
    (
        SELECT  ID, FromDate, ToDate, 0 AS Seed FROM #Test
        UNION   ALL
        SELECT  ID, DATEADD(dd, 1, FromDate), ToDate, Seed + 1
        FROM    DateTable
        WHERE   DATEADD(dd, 1, FromDate) <= ToDate
    )
    SELECT  --*
            ROW_NUMBER() OVER (ORDER BY ID, Seed) SN, FromDate AS Dates
    FROM    DateTable
    

    【讨论】:

    • 这可以在没有 CTE 的情况下完成吗,因为我必须将所有这些查询与其他一些查询联合起来。如果我不需要ID 列,该怎么办。
    • 您可以在 CTE 查询中使用连接;你能给我一个例子吗?如果您不需要该 ID 列,请将其删除 - 我只是认为当您获得两个重叠范围时您可能有兴趣了解日期源,因为您将获得“重复”日期
    • 是的,这正是我遇到的。如果我在两边都有相同的日期并且没有 ID 列,则重复行。
    • 你如何处理重复的日期?您可以使用 DISTINCT 忽略它们,或者您可以取消注释 --* 以查看发生了什么
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-11-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多