【问题标题】:Finding time overlaps using SQL使用 SQL 查找时间重叠
【发布时间】:2014-12-04 15:54:25
【问题描述】:

我有一个由一系列时间数据组成的表,如下所示:

+--------+--------------------+---------------------+
| person | start              | end                 |
+--------+--------------------+---------------------+
| a      |2014-12-04 13:00:00 | 2014-12-04 14:00:00 |
| a      |2014-12-04 13:30:00 | 2014-12-04 14:30:00 |
| b      |2014-12-04 13:00:00 | 2014-12-04 14:00:00 |
| b      |2014-12-04 13:30:00 | 2014-12-04 14:30:00 |
| b      |2014-12-04 14:00:00 | 2014-12-04 15:00:00 |
| a      |2014-12-04 19:00:00 | 2014-12-04 20:00:00 |
| a      |2014-12-04 19:30:00 | 2014-12-04 20:30:00 |
+--------+--------------------+---------------------+

我想查找时间重叠并输出以下内容:

+--------+--------------------+---------------------+
| person | start              | end                 |
+--------+--------------------+---------------------+
| a      |2014-12-04 13:00:00 | 2014-12-04 14:30:00 |
| b      |2014-12-04 13:00:00 | 2014-12-04 15:00:00 |
| a      |2014-12-04 19:00:00 | 2014-12-04 20:30:00 |
+--------+--------------------+---------------------+

所以我正在寻找一个查询来查找时间间隔重叠的实例,我想查看与时间间隔相关的人以及最早的时间段和最新的时间段。

很难解释,但我希望你能明白!

【问题讨论】:

  • 您使用的是哪个 DBMS?后格雷斯?甲骨文?

标签: sql datetime sqlite


【解决方案1】:

如果您有支持WITH RECURSIVE 的最新版本的sqlite(在sqlfiddle.com 上不起作用),这很棘手,但可能:

create table intervals (
  person text,
  start timestamp,
  end timestamp
);

insert into intervals values ('a', '2014-12-04 13:00:00', '2014-12-04 14:00:00');
insert into intervals values ('a', '2014-12-04 13:30:00', '2014-12-04 14:30:00');
insert into intervals values ('b', '2014-12-04 13:00:00', '2014-12-04 14:00:00');
insert into intervals values ('b', '2014-12-04 13:30:00', '2014-12-04 14:30:00');
insert into intervals values ('b', '2014-12-04 14:00:00', '2014-12-04 15:00:00');
insert into intervals values ('a', '2014-12-04 19:00:00', '2014-12-04 20:00:00');
insert into intervals values ('a', '2014-12-04 19:30:00', '2014-12-04 20:30:00');

WITH RECURSIVE
 merged_intervals(person, start, end) AS (
    select person, start, end
    from intervals

    where not exists (
        select * from intervals i2 
        where i1.person=i2.person
        and (i2.start<i1.start and i2.end>=i1.start)
    )

 UNION ALL
    select i1.person, i1.start, i2.end
    from merged_intervals i1, intervals i2 
    where i1.start<=i2.start and i1.end>i2.start and i1.end<i2.end
    and i1.person=i2.person
)
select * from merged_intervals i1
where not exists (
    select * from merged_intervals i2 
    where i1.person=i2.person
    and (
        (i2.start<i1.start and i2.end>i1.start)
        or
        (i2.end>i1.end and i2.start<i1.end)
        )
    )
order by start, person
;

【讨论】:

  • 这似乎可行(尽管我不能声称自己完全理解!)。我正在运行 SQLite 版本 3.7.16.2,但必须升级到最新版本才能执行此操作。如果有人感兴趣,在SQLite 3.8.3 中添加了对 WITH 子句的支持
  • 我遇到了问题。这对示例数据非常有效,但是当我尝试在我的实际数据库(其中有超过 5500 行)上运行它时收到以下消息: 数据库或磁盘已满 顺便说一下,磁盘未满!上面有 20GB 的免费空间。有什么想法吗?
  • 我添加了一个可以提高性能的 where 子句,告诉我它是否可以解决您的问题(如果它仍然有效:-)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-11-14
  • 1970-01-01
  • 1970-01-01
  • 2014-08-29
  • 1970-01-01
  • 2015-01-07
  • 1970-01-01
相关资源
最近更新 更多