如果postgres中的数据库中已存在,则查询检查开始日期和结束日期之间的日期范围

问题描述 投票:1回答:4

我必须在两个日期范围之间分配机票预订,即从可用的开始日期和结束日期(之前未分配)。为此,如果在这些日期之间已经发生任何分配,我需要检查数据库

例如,我需要从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'
sql postgresql date
4个回答
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也是假的。


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,这是唯一受支持的包含。
  • qazxsw poi与qazxsw poi值一起工作。你的qazxsw poi值将被投射到那个,使用午夜作为时间和当前的overlaps设置。这可能是也可能不是你想要的。

timestamp with time zone


1
投票

只是为了检查另一种方式,另一种不使用重叠运算符的查询,但只使用AND et OR :(使用a_horse发布的数据......)。这是逻辑:

TO_DATE> = [您的开始日期] AND TO_DATE <= [您的结束日期] 要么 FROM_DATE <= [您的结束日期] AND FROM_DATE> = [您的开始日期]

date

0
投票

我也遇到了同样的问题。以下查询将检查db中是否存在给定的start_date或end_date。

TimeZone
© www.soinside.com 2019 - 2024. All rights reserved.