使用SQL查找时间重叠

时间:2014-12-04 15:54:25

标签: sql datetime sqlite

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

+--------+--------------------+---------------------+
| 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 |
+--------+--------------------+---------------------+

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

狡猾解释,但我希望你得到这个小说!

1 个答案:

答案 0 :(得分:0)

如果你有一个支持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
;