【问题标题】:Calculate missing date ranges and overlapping date ranges between two dates计算两个日期之间缺失的日期范围和重叠的日期范围
【发布时间】:2009-06-22 06:18:34
【问题描述】:

我的数据库中有以下一组日期 (dd/MM/yyyy) 匹配事件:

eventId startDate endDate 1 2009 年 2 月 5 日 2009 年 10 月 5 日 2 2009 年 8 月 5 日 2009 年 12 月 5 日 3 2009 年 10 月 5 日 2009 年 12 月 5 日 4 2009 年 5 月 21 日 2009 年 5 月 21 日 5 25/05/2009 空 6 2009 年 1 月 6 日 2009 年 3 月 6 日

事件有开始和结束日期(时间无关紧要),NULL endDate 表示事件仍在进行中。

我想确定的是两个任意日期之间的日期范围,其中 a) 没有事件和 b) 事件重叠。

因此,对于 01/04/2009 - 30/06/2009 的输入日期范围,我希望得到以下结果:

无事件:01/04/2009 - 01/05/2009 重叠:08/05/2009 - 10/05/2009 重叠:10/05/2009 - 12/05/2009 无事件:2009 年 5 月 13 日 - 2009 年 5 月 20 日 无事件:22/05/2009 - 24/05/2009 重叠:01/06/2009 - 03/06/2009

请注意,两个相邻的重叠范围作为一个结果是可以接受的。

谁能帮我用一个 SQL 算法来生成这个结果集?

编辑:目标平台数据库是 SQL Server 2005。日期记录为 10/05/2009 00:00:00,这意味着事件在 10/5/2009 00:00:00 和 10 之间的某个时间结束/5/2009 23:59:59。开始日期也是如此。因此,输入日期范围也可以读取为 01/04/2009 00:00:00 - 30/06/2009 23:59:59。

【问题讨论】:

  • 您将在哪个数据库平台上运行此查询?

标签: sql sql-server algorithm tsql


【解决方案1】:

这是在SQL Server 中展平相交时间跨度的函数的一个小变化:

这是SQL Server 中基于游标的方法比基于集合的方法更快的罕见情况之一:


CREATE FUNCTION mytable(@p_from DATETIME, @p_till DATETIME)
RETURNS @t TABLE
        (
        q_type VARCHAR(20) NOT NULL,
        q_start DATETIME NOT NULL,
        q_end DATETIME NOT NULL
        )
AS
BEGIN
        DECLARE @qs DATETIME
        DECLARE @qe DATETIME
        DECLARE @ms DATETIME
        DECLARE @me DATETIME
        DECLARE cr_span CURSOR FAST_FORWARD
        FOR
        SELECT  startDate, endDate
        FROM    mytable
        WHERE   startDate BETWEEN @p_from AND @p_till
        ORDER BY
                startDate 
        OPEN    cr_span
        FETCH   NEXT
        FROM    cr_span
        INTO    @qs, @qe
        SET @ms = @qs
        SET @me = @qe
        WHILE @@FETCH_STATUS = 0
        BEGIN
                FETCH   NEXT
                FROM    cr_span
                INTO    @qs, @qe
                IF @qs > @me
                BEGIN
                        INSERT
                        INTO    @t
                        VALUES ('overlap', @ms, @me)
                        INSERT
                        INTO    @t
                        VALUES ('gap', @me, @qs)
                        SET @ms = @qs
                END
                SET @me = CASE WHEN @qe > @me THEN @qe ELSE @me END
        END
        IF @ms IS NOT NULL
        BEGIN
                INSERT
                INTO    @t
                VALUES  (@ms, @me)
        END
        CLOSE   cr_span
        RETURN
END
GO

此函数将每个连续的相交范围集压缩为一个范围,并返回范围和以下间隙。

【讨论】:

  • Quassnoi 的回复是解决问题的方法吗?如果是,函数中数据表的名称是什么。
【解决方案2】:

在没有真正理解您要解决什么问题的情况下,这是我对一些问题的解决方案:

  1. 创建将返回一年中所有日期的表函数 (UDF) “所有日期”。
  2. 通过将事件内部连接到所有日期where the date is between event's start and end dates,将您的事件转换为单独的日期(一个事件行将变成与其中天数一样多的行)...保留原始 eventId。
  3. (再次)将 event-dates 与 all-dates 进行外部连接,以找出差距或遗漏。
  4. where dates are same but eventId is not 上与他们自己一起加入活动日期以查找重叠。

【讨论】:

    【解决方案3】:

    我的可怜,使用 postgresql,你可以简单地做到这一点:

    (start1, end1) 重叠 (start2, end2) (start1, length1) 重叠 (start2, length2)

    当两个时间段(由它们的端点定义)重叠时,此表达式产生 true,当它们不重叠时产生 false。端点可以指定为日期、时间或时间戳对;或作为日期、时间或时间戳,后跟间隔。

    选择(日期“2001-02-16”,日期“2001-12-21”)重叠 (日期'2001-10-30',日期'2002-10-30'); 结果:真 选择(日期“2001-02-16”,间隔“100 天”)重叠 (日期'2001-10-30',日期'2002-10-30'); 结果:假

    但是在sql server下,我不知道... 对不起

    【讨论】:

      猜你喜欢
      • 2021-08-15
      • 1970-01-01
      • 1970-01-01
      • 2021-09-18
      • 2023-01-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-02-14
      相关资源
      最近更新 更多