我必须在两个日期范围之间分配机票预订,即从可用的开始日期和结束日期(之前未分配)。 为此,我需要检查数据库中是否已经在这些日期之间发生任何分配
例如,我需要从2017/04/20到2017/04/25分配机票预订。在插入此记录之前,我需要检查以前在2017/04/20开始日期之前是否有任何预订截止日期2017/04/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'
答案 0 :(得分:2)
您的查询未给出预期结果,因为您只测试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
个值。您的date
值会被投放到该值,使用午夜作为时间和时间。当前的TimeZone
设置。这可能是也可能不是你想要的。答案 1 :(得分:1)
只是为了检查另一种方式,另一个不使用重叠运算符的查询,但只有AND et OR: (使用a_horse发布的数据......)。这是逻辑:
TO_DATE&gt; = [您的开始日期] AND TO_DATE&lt; = [您的结束日期]
OR
FROM_DATE&lt; = [您的结束日期] AND FROM_DATE&gt; = [您的开始日期]
select *
from bookings
where to_date>=date '2017-04-18' AND to_date<=date '2017-04-19'
OR from_date<= date '2017-04-19' AND from_date>=date '2017-04-18';
select *
from bookings
where to_date>=date '2017-04-20' AND to_date<=date '2017-04-25'
OR from_date<= date '2017-04-25' AND from_date>=date '2017-04-20';
答案 2 :(得分:0)
使用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 :(得分:0)
我也有同样的问题。以下查询将检查db中是否存在给定的start_date或end_date。
$start_date = '2010-01-01';
$end_date = '2017-01-01';
SELECT * FROM `ticket_history` WHERE
($start_date <= start_date AND $start_date <= end_date AND
(($end_date >= start_date AND $end_date >= end_date) OR ($end_date >=
start_date AND $end_date <= end_date))) OR
($start_date >= start_date AND $start_date <= end_date AND
(($end_date >= start_date AND $end_date >= end_date) OR ($end_date >=
start_date AND $end_date <= end_date)))