【问题标题】:Check if two date intervals intersect检查两个日期间隔是否相交
【发布时间】:2013-09-08 11:47:45
【问题描述】:

我需要检查 MySQL 以查看两个日期间隔是否相交。 为了更好地解释我的问题:我有一个事件管理模块。如果我们有这样添加的事件:

开始日期:'2013-09-09 08:00:00'

结束日期:'2013-09-09 10:00:00'

现在我想添加另一个类似这样的事件:

案例A:

开始日期:'2013-09-09 09:00:00'

结束日期:'2013-09-09 11:00:00'

或者像这样:

案例 B:

开始日期:'2013-09-09 07:00:00'

结束日期:'2013-09-09 12:00:00'

我不应该这样做,因为在那个时间间隔 (08-10) 内已经添加了一个事件

对于第一个示例 (case A),我通过这样做解决了问题:

SELECT * FROM `events` as e 
    where 
    '2013-09-09 08:00:00' between e.ev_date_start and e.ev_date_end -- date start
    OR
    '2013-09-09 11:00:00' between e.ev_date_start and e.ev_date_end -- date end

但是对于第二种情况 (case B) 我无法弄清楚...

【问题讨论】:

    标签: mysql sql select


    【解决方案1】:

    这个想法是检查它们是否不相交,然后取反。

    NOT ('2013-09-09 08:00:00' >= e.ev_date_end OR e.ev_date_start >= '2013-09-09 11:00:00')
    

    逻辑上等价于

    '2013-09-09 08:00:00' < e.ev_date_end AND e.ev_date_start < '2013-09-09 11:00:00'
    

    【讨论】:

      【解决方案2】:

      只测试已经分配的时间块或要分配的时间块的开始时间不落在彼此之间。

      select * from `events` as e 
      where '2013-09-09 08:00:00' between e.ev_date_start and e.ev_date_end
      or e.ev_date_start between '2013-09-09 08:00:00'and '2013-09-09 11:00:00'
      

      【讨论】:

      • 就像'2013-09-09 08:00:00' &lt; e.ev_date_end AND e.ev_date_start &lt; '2013-09-09 11:00:00'一样简单
      • 这实际上是错误的。还有一种情况。让我们将日期命名为“AS”(A 开始)、“BS”(B 开始)、“AE”、(A 结束)和“BE”(B 结束)。可能的相交组合是: AS BS AE BE BS AS AE BS AS AE BE AS BS BE AE 所以你需要:'AS' BETWEEN 'BS' AND 'BE' OR 'AE' BETWEEN 'BS' AND 'BE ' 或 'BS' 在 'AS' 和 'AE' 之间
      【解决方案3】:

      要同时涵盖它们,您需要在 WHERE 子句中添加 4 条语句:

      select *
        from `events` as e 
       where '2013-09-09 07:00:00' between e.ev_date_start and e.ev_date_end
          or '2013-09-09 12:00:00' between e.ev_date_start and e.ev_date_end
          or e.ev_date_start between '2013-09-09 07:00:00' and '2013-09-09 12:00:00'
          or e.ev_date_end between '2013-09-09 07:00:00' and '2013-09-09 12:00:00'
      

      它可能看起来更简单:

      select *
        from `events` as e 
       where @start between e.ev_date_start and e.ev_date_end
          or @end between e.ev_date_start and e.ev_date_end
          or e.ev_date_start between @start and @end
          or e.ev_date_end between @start and @end
      

      【讨论】:

        【解决方案4】:

        请记住,您预先保证(通过一些 UI 验证)2013-09-09 12:00:00 大于 2013-09-09 07:00: 00您可以这样简单地划过支票:

        WHERE 1
        AND '2013-09-09 07:00:00' <= e.ev_date_end 
        AND '2013-09-09 12:00:00' >= e.ev_date_start
        

        这种检查更加简单快捷。无需搞乱 OR 语句或其他复杂的逻辑。始终牢记 OR 会严重损害 SQL 的性能。

        【讨论】:

          【解决方案5】:

          一个小例子:

          我想看看这两个mysql日期是否与数据库上的日期相交;

          '2015-02-01 00:00:00', '2015-02-28 23:59:59'

          在 phpMyAdmin 或 MySQL Workbench 上执行的查询;

          CREATE TEMPORARY TABLE `date_temp`
          (
            `id` int(5) NOT NULL AUTO_INCREMENT,
            `date_1` DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00' COMMENT 'Start date',
            `date_2` DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00' COMMENT 'Expiration date',
            PRIMARY KEY (`id`)
          ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
          
          INSERT INTO `date_temp` (`date_1`, `date_2`)
          VALUES 
          ('2015-01-01 00:00:00', '2015-01-30 23:59:59'),
          ('2015-02-02 00:00:00', '2015-02-27 23:59:59'),
          ('2015-03-02 00:00:00', '2015-03-31 23:59:59'),
          ('2015-01-15 00:00:00', '2015-03-15 23:59:59'),
          ('2015-01-15 00:00:00', '2015-02-15 23:59:59'),
          ('2015-02-15 00:00:00', '2015-03-15 23:59:59');
          
          SELECT * 
          FROM `date_temp`
          WHERE 
          NOT 
          (
              ('2015-02-01 00:00:00' > `date_2`) OR 
              (`date_1` > '2015-02-28 23:59:59') OR 
              (`date_2` < `date_1`) OR 
              ('2015-02-28 23:59:59' < '2015-02-01 00:00:00')
          );
          
          DROP TABLE `date_temp`;
          

          查询创建一个表,插入一些数据并测试这两个日期是否与表上存在的日期相交。然后清空表。

          【讨论】:

            猜你喜欢
            • 2018-02-01
            • 1970-01-01
            • 2014-06-28
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2013-04-11
            相关资源
            最近更新 更多