我必须在两个日期范围之间分配机票预订,即从可用的开始日期和结束日期(之前未分配)。为此,如果在这些日期之间已经发生任何分配,我需要检查数据库
例如,我需要从2017/04/20到2017/04/25分配机票预订。在插入此记录之前,我需要检查以前在2017/04/20开始日期和结束日期之间是否有任何预订2017年4月25日
我尝试过以下查询。但它没有给出正确的结果
select "id"
from "table"
where "from_date" >= '2017-04-20'
and "to_date" > '2017-04-20'
and "from_date" < '2017-04-25'
and "to_date" <= '2017-04-25'
使用overlaps
运算符:
select count(*) = 0 as allow_booking
from "table"
where (from_date, to_date) overlaps (date '2017-04-20', date '2017-04-25');
这也将照顾不完全属于测试范围的预订。
如果允许预订,查询将返回true
,如果不允许,则返回false
。
例子:
create table bookings
(
id serial,
from_date date,
to_date date
);
insert into bookings
(from_date, to_date)
values
(date '2017-04-20', date '2017-04-20'),
(date '2017-04-20', date '2017-04-24'),
(date '2017-04-26', date '2017-04-29');
然后是以下
select *
from bookings
where (from_date, to_date) overlaps (date '2017-04-18', date '2017-04-19');
什么都不返回,所以,count(*) = 0
返回true
以下查询:
select *
from bookings
where (from_date, to_date) overlaps (date '2017-04-20', date '2017-04-25');
收益:
id | from_date | to_date
---+------------+-----------
1 | 2017-04-20 | 2017-04-20
2 | 2017-04-20 | 2017-04-24
所以count(*) = 0
回归false
和查询:
select *
from bookings
where (from_date, to_date) overlaps (date '2017-04-27', date '2017-04-28');
将返回:
id | from_date | to_date
---+------------+-----------
3 | 2017-04-26 | 2017-04-29
而对于那个count(*) = 0
也是假的。
您的查询未给出预期结果,因为您只测试3种(或4种)重叠/交叉方式中的1种:
existing date periods: +--------------+ +-----+ +----+ +-----+
contains contained by touches
testing periods: +------+ +------------+ +---------+
要测试每种可能的重叠方式,您可以使用daterange
的重叠运算符:&&
select count(*)
from booking
where daterange(from_date, to_date, '[]') && daterange('2017-04-20', '2017-04-25', '[]');
但要注意:只使用这种手动检查不会阻止在高并发性中插入重叠的日期范围。在此测试之后和实际插入之前有一个(小)窗口,用于插入冲突行的另一个并发语句。为了避免这种情况,你可以使用exclusion constraints:
alter table booking
add constraint exclude_overlapping_bookings
exclude using gist (daterange(from_date, to_date, '[]') with &&);
注意:daterange
的重叠运算符(&&
)的工作方式与@a_horse_with_no_name提到的overlaps
运算符相同。除了:
[)
,表示:下限是包含的,但上限是独占的。使用overlaps
,这是唯一受支持的包含。overlaps
设置。这可能是也可能不是你想要的。timestamp with time zone
只是为了检查另一种方式,另一种不使用重叠运算符的查询,但只使用AND et OR :(使用a_horse发布的数据......)。这是逻辑:
TO_DATE> = [您的开始日期] AND TO_DATE <= [您的结束日期] 要么 FROM_DATE <= [您的结束日期] AND FROM_DATE> = [您的开始日期]
date
我也遇到了同样的问题。以下查询将检查db中是否存在给定的start_date或end_date。
TimeZone