从如何在PostgreSql的预订表中找到第一次空闲时间的最佳答案中选择
create table reservation (during tsrange, EXCLUDE USING gist (during WITH &&) );
用于查找在给定日期和时间(2012年11月17日:在下面的示例中)开始的时间表中的间隔,它还可以查找周六,周日和公共假日。表中定义了公众假期
create table pyha ( pyha date primary key)
如何也排除周末和公共假期?
硬编码空闲时间作为查询之类的保留时间
with gaps as ( select upper(during) as start, lead(lower(during),1,upper(during)) over (ORDER BY during) - upper(during) as gap from ( select during from reservation union all values ('(,2012-11-17 8:)'::tsrange), -- given date and hour from which to find free work time ('[2012-11-17 0:,2012-11-18 24:)'::tsrange), -- exclude saturday ('[2012-11-18 0:,2012-11-19 8:)'::tsrange), -- exclude sunday ('[2012-11-19 18:,2012-11-20 8:)'::tsrange), ('[2012-11-20 18:,2012-11-21 8:)'::tsrange), ('[2012-11-21 18:,2012-11-22 8:)'::tsrange), ('[2012-11-22 18:,2012-11-23 8:)'::tsrange), ('[2012-11-23 18:,2012-11-24 24:)'::tsrange), ('[2012-11-24 0:,2012-11-25 24:)'::tsrange), -- exclude saturday ('[2012-11-25 0:,2012-11-26 8:)'::tsrange) -- exclude sunday ) as x ) select * from gaps where gap > '0'::interval order by start
对于每个空闲时间范围,都需要在联合中有单独的行。
从给定的日期和时间开始,在工作日和工作时间(8:00 .. 18:00)中返回空闲时间的最佳方法是哪种?
更新
选择答案时,总是在8:00返还空闲时间。如何在指定开始日期的指定开始时间之前返回空闲时间,例如,如果开始时间为9,则不返回2012-11-19 9:00之前的空闲时间?开始时间可能只有值8,9,10,11,12,13,14,15,16或17
即使2012-11-19 8:00(如果有空)也应返回2012-11-19 9:00。仅在2012-11-19的9:00没有空闲时间并且在随后的工作日中第一次空闲8:00时,才应返回8:00。
我试图通过将 2012-11-19 9: 添加到两个地方来解决此问题,如下查询所示,但此查询仍在2012-11-19 8:00返回空闲时间。如何解决此问题,使其在2012-11-19 9:00返回空闲时间?
create table reservation (during tsrange, EXCLUDE USING gist (during WITH &&) ); create table pyha ( pyha date primary key); with gaps as ( select upper(during) as start, lead(lower(during),1,upper(during)) over (ORDER BY during) - upper(during) as gap from ( select during from reservation where upper(during)>= '2012-11-19 9:' union all values ('(,2012-11-19 9:)'::tsrange) union all select unnest(case when pyha is not null then array[tsrange(d, d + interval '1 day')] when date_part('dow', d) in (0, 6) then array[tsrange(d, d + interval '1 day')] else array[tsrange(d, d + interval '8 hours'), tsrange(d + interval '18 hours', d + interval '1 day')] end) from generate_series( '2012-11-19'::timestamp without time zone, '2012-11-19'::timestamp without time zone+ interval '3 month', interval '1 day' ) as s(d) left join pyha on pyha = d::date ) as x ) select start, date_part('epoch', gap) / (60*60) as hours from gaps where gap > '0'::interval order by start
更新2
我尝试更新答案,但返回错误数据。完整的测试用例是:
create temp table reservation ( during tsrange ) on commit drop; insert into reservation values( '[2012-11-19 11:00:00,2012-11-19 11:30:00)'::tsrange ); with gaps as ( select upper(during) as start, lead(lower(during),1,upper(during)) over (ORDER BY during) - upper(during) as gap from ( select during from reservation union all select unnest(case when pyha is not null then array[tsrange(d, d + interval '1 day')] when date_part('dow', d) in (0, 6) then array[tsrange(d, d + interval '1 day')] when d::date = DATE'2012-11-19' then array[ tsrange(d, '2012-11-19 12:'), -- must return starting at 12:00 tsrange(d + interval '18 hours', d + interval '1 day')] else array[tsrange(d, d + interval '8 hours'), tsrange(d + interval '18 hours', d + interval '1 day')] end) from generate_series( DATE'2012-11-19'::timestamp without time zone, DATE'2012-11-19'::timestamp without time zone+ interval '3 month', interval '1 day' ) as s(d) left join pyha on pyha = d::date ) as x ) select start, date_part('epoch', gap) / (60*60) as tunde from gaps where gap > '0'::interval order by start
观察到的第一行:
"2012-11-19 11:30:00"
预期的 :
"2012-11-19 12:00:00"
怎么修 ?
您可以使用generate_series()函数来掩盖非工作时间:
with gaps as ( select upper(during) as start, lead(lower(during),1,upper(during)) over (ORDER BY during) - upper(during) as gap from ( select during from reservation union all select unnest(case when pyha is not null then array[tsrange(d, d + interval '1 day')] when date_part('dow', d) in (0, 6) then array[tsrange(d, d + interval '1 day')] when d::date = '2012-11-14' then array[tsrange(d, d + interval '9 hours'), tsrange(d + interval '18 hours', d + interval '1 day')] else array[tsrange(d, d + interval '8 hours'), tsrange(d + interval '18 hours', d + interval '1 day')] end) from generate_series( '2012-11-14'::timestamp without time zone, '2012-11-14'::timestamp without time zone + interval '2 week', interval '1 day' ) as s(d) left join pyha on pyha = d::date ) as x ) select * from gaps where gap > '0'::interval order by start
让我解释一些棘手的部分:
pyha
date_part('dow', d)
根据您的更新,我添加了另一个问题when来case:
when
case
when d::date = '2012-11-14' then array[tsrange(d, d + interval '9 hours'), tsrange(d + interval '18 hours', d + interval '1 day')]
这个想法是为开始日期(d::date = '2012-11-14')产生不同的时间间隔:(0..9)和(18..24)
d::date = '2012-11-14'