如何找到在PostgreSQL在保留表第一空闲时间(How to find first free t

2019-08-02 18:09发布

预订表包含保留的开始日期,开始时间和持续时间。 启动时间是半小时的增量在工作时间8:00 .. 18:00个工作日内。 持续时间也将在一天半小时的增量。

CREATE TABLE reservation (
  startdate date not null,  -- start date
  starthour numeric(4,1) not null , -- start hour 8 8.5 9 9.5  ..  16.5 17 17.5
  duration  Numeric(3,1) not null, -- duration by hours 0.5 1 1.5 .. 9 9.5 10
  primary key (startdate, starthour)
);

如果所需的表结构可以改变。

如何找到在表中第一个空闲半小时未保留? 如果公式包含的表

startdate   starthour  duration 
14          9           1              -- ends at 9:59
14          10          1.5            -- ends at 11:29, e.q there is 30 minute gap before next
14          12          2
14          16          2.5

结果应该是:

starthour  duration
11.5       0.5

大概的PostgreSQL 9.2窗函数应该用来寻找第一行,其starthour比前一行starthour +时长
如何写返回此信息select语句?

Answer 1:

Postgres的9.2具有范围类型,我会建议使用它们。

create table reservation (reservation tsrange);
insert into reservation values 
('[2012-11-14 09:00:00,2012-11-14 10:00:00)'), 
('[2012-11-14 10:00:00,2012-11-14 11:30:00)'), 
('[2012-11-14 12:00:00,2012-11-14 14:00:00)'), 
('[2012-11-14 16:00:00,2012-11-14 18:30:00)');

ALTER TABLE reservation ADD EXCLUDE USING gist (reservation WITH &&);

“EXCLUDE USING要旨”创建其不允许到插入图示重叠条目索引。 您可以使用下面的查询来寻找差距(vyegorov的查询的变体):

with gaps as (
  select 
    upper(reservation) as start, 
    lead(lower(reservation),1,upper(reservation)) over (ORDER BY reservation) - upper(reservation) as gap 
  from (
    select * 
    from reservation 
    union all values 
      ('[2012-11-14 00:00:00, 2012-11-14 08:00:00)'::tsrange), 
      ('[2012-11-14 18:00:00, 2012-11-15 00:00:00)'::tsrange)
  ) as x
) 
select * from gaps where gap > '0'::interval;

工会的所有值'屏蔽了非工作时间,因此您只能上午8点和18pm之间保留。

下面是结果:

        start        |   gap    
---------------------+----------
 2012-11-14 08:00:00 | 01:00:00
 2012-11-14 11:30:00 | 00:30:00
 2012-11-14 14:00:00 | 02:00:00

文档链接: - http://www.postgresql.org/docs/9.2/static/rangetypes.html “范围类型” - https://wiki.postgresql.org/images/7/73/Range-types-pgopen- 2012.pdf



Answer 2:

也许不是最好的查询,但你想要做什么:

WITH
times AS (
    SELECT startdate sdate,
        startdate + (floor(starthour)||'h '||
           ((starthour-floor(starthour))*60)||'min')::interval shour,
        startdate + (floor(starthour)||'h '||
           ((starthour-floor(starthour))*60)||'min')::interval 
           + (floor(duration)||'h '||
             ((duration-floor(duration))*60)||'min')::interval ehour
      FROM reservation),
gaps AS (
    SELECT sdate,shour,ehour,lead(shour,1,ehour)
       OVER (PARTITION BY sdate ORDER BY shour) - ehour as gap
      FROM times)
SELECT * FROM gaps WHERE gap > '0'::interval;

一些注意事项:

  1. 这将是最好不要分开时间和事件的数据。 如果你有,那么使用标准的类型;
  2. 如果它是不可能去与标准类型,创建函数转换numeric小时为time格式。


文章来源: How to find first free time in reservations table in PostgreSql