检查SQL中是否可以预订(Postgresql)

时间:2015-09-26 10:40:46

标签: sql database postgresql gaps-in-data

我预订了这样看的记录:

  id  |        from         |         to
------+---------------------+---------------------
  101 | 2015-09-24 08:00:00 | 2015-09-24 09:30:00
 2261 | 2015-09-24 09:00:00 | 2015-09-24 10:00:00
 4061 | 2015-09-24 10:00:00 | 2015-09-24 10:30:00
  204 | 2015-09-24 12:00:00 | 2015-09-24 13:30:00
 2400 | 2015-09-24 13:30:00 | 2015-09-24 14:00:00
 4224 | 2015-09-24 14:00:00 | 2015-09-24 14:30:00
  309 | 2015-09-24 16:00:00 | 2015-09-24 17:30:00
 2541 | 2015-09-24 17:00:00 | 2015-09-24 18:00:00

我正在寻找最佳查询来查找问题:

Is this possible to find a timeslot with duration x (ie. 30 minutes) in above records?

我有想法使用postgres数组或时间范围,但仍然在寻找更好的想法......

编辑:我会提供假冒的'预订作为界限,但如果您有更好的想法,请写下:))

5 个答案:

答案 0 :(得分:1)

这样的事情:

select t1.*
from tablename t1
where (select min("from") from tablename t2
       where t2."from" > t1."from") >= t1."to" + interval '30' minute

即。如果与下一行的差距为> = 30分钟,则返回一行。

注意fromto是ANSI SQL中的保留字,这就是为什么它们被分隔为"from""to"

答案 1 :(得分:1)

这是一个使用分析功能的解决方案,它提供了所有没有预订的窗口:

observer

SQL小提琴here

答案 2 :(得分:0)

您可以使用lag()功能:

Unchecked runtime.lastError while running notifications.create: Adding buttons to notifications is not supported.

选择select *, book_start- previous_book_end timeslot from ( select id, "from" book_start, "to" book_end, lag("to") over (order by "to") previous_book_end from test ) sub order by book_end id | book_start | book_end | previous_book_end | timeslot ------+---------------------+---------------------+---------------------+----------- 101 | 2015-09-24 08:00:00 | 2015-09-24 09:30:00 | | 2261 | 2015-09-24 09:00:00 | 2015-09-24 10:00:00 | 2015-09-24 09:30:00 | -00:30:00 4061 | 2015-09-24 10:00:00 | 2015-09-24 10:30:00 | 2015-09-24 10:00:00 | 00:00:00 204 | 2015-09-24 12:00:00 | 2015-09-24 13:30:00 | 2015-09-24 10:30:00 | 01:30:00 2400 | 2015-09-24 13:30:00 | 2015-09-24 14:00:00 | 2015-09-24 13:30:00 | 00:00:00 4224 | 2015-09-24 14:00:00 | 2015-09-24 14:30:00 | 2015-09-24 14:00:00 | 00:00:00 309 | 2015-09-24 16:00:00 | 2015-09-24 17:30:00 | 2015-09-24 14:30:00 | 01:30:00 2541 | 2015-09-24 17:00:00 | 2015-09-24 18:00:00 | 2015-09-24 17:30:00 | -00:30:00 (8 rows) 行:

timeslots >= '30m'::interval

答案 3 :(得分:0)

非标准自我加入:

SELECT
    ll.ts_to AS ts_from
    , hh.ts_from AS ts_to
FROM bookings ll
JOIN bookings hh
    -- enough space 
    ON hh.ts_from >= ll.ts_to + '30 min'::interval
    -- and nothing in between
    AND NOT EXISTS (
        SELECT * FROM bookings nx
        WHERE nx.ts_from >= ll.ts_to
        AND nx.ts_to <= hh.ts_from
        )
UNION ALL   -- before the first
SELECT '-infinity'::timestamp AS ts_from
       , MIN(ts_from) AS ts_to
    FROM bookings
UNION ALL   -- after the last
SELECT MAX(ts_to) AS ts_from
       , 'infinity'::timestamp AS ts_to
    FROM bookings
ORDER BY 1,2
    ;

答案 4 :(得分:0)

生成您的广告位,然后离开加入它们。 http://sqlfiddle.com/#!15/12bfa

create table t (id integer, "from" timestamp, "to" timestamp);

insert into t values 
(101 , '2015-09-24 08:00:00' , '2015-09-24 09:30:00' ),
(2261 , '2015-09-24 09:00:00' , '2015-09-24 10:00:00' ),
(4061 , '2015-09-24 10:00:00' , '2015-09-24 10:30:00' ),
( 204 , '2015-09-24 12:00:00' , '2015-09-24 13:30:00' ),
(2400 , '2015-09-24 13:30:00' , '2015-09-24 14:00:00' ),
(4224 , '2015-09-24 14:00:00' , '2015-09-24 14:30:00' ),
( 309 , '2015-09-24 16:00:00' , '2015-09-24 17:30:00' ),
(2541 , '2015-09-24 17:00:00' , '2015-09-24 18:00:00' );

SELECT time_slots.t,
       time_slots.t + interval '30 minutes'
FROM generate_series(date'2015-09-24',date'2015-09-25' - interval '30 minutes' ,interval '30 minutes') AS time_slots(t)
LEFT JOIN t ON (time_slots.t BETWEEN t."from" AND t."to")
WHERE t.id IS NULL;


SELECT time_slots.t,
       time_slots.t + interval '30 minutes'
FROM generate_series(date'2015-09-24',date'2015-09-25' - interval '30 minutes',interval '30 minutes') AS time_slots(t)
LEFT JOIN t ON ((time_slots.t,
                 time_slots.t + interval '30 minutes') OVERLAPS (t."from",
                                                                 t."to"))
WHERE t.id IS NULL;