简体   繁体   English

postgreSQL-检查一个日期间隔是否与每行间隔数组中的日期间隔不重叠

[英]postgreSQL - Checking if one date interval does not overlap a date interval in array of intervals for each row

PostgreSQL(9.6), I am trying to check whether a date interval PostgreSQL(9.6),我正在尝试检查日期间隔

('2018-11-18 12:00','2018-11-20 12:00')

does not overlap any of the following date intervals in the array 不与数组中的以下任何日期间隔重叠

{('2018-11-21 12:00','2018-11-23 12:00'),('2018-11-19 12:00','2018-11-20 12:00')}

The elements in the array are composite: 数组中的元素是复合的:

CREATE TYPE reservation AS (
    checkIn TIMESTAMP WITHOUT TIME ZONE,
    checkOut TIMESTAMP WITHOUT TIME ZONE
)

Here is the rooms table: 这是房间表:

CREATE TABLE rooms (
rId roomId PRIMARY KEY,
hRef hotelId NOT NULL,
rNo roomNo NOT NULL,
rType roomType,
numPeople INTEGER,
rBedOptions roomBed[],
reservations reservation[],
priceNight FLOAT,
FOREIGN KEY (hRef) REFERENCES hotels(hId) ON UPDATE CASCADE ON DELETE SET NULL  
)

INSERT INTO rooms VALUES
('R001','H001','101','one-bedroom',1,
ARRAY[row('1 twin')::roomBed],
ARRAY[
      row('2018-11-21 12:00','2018-11-23 12:00')::reservation,
      row('2018-11-19 12:00','2018-11-20 12:00')::reservation],
450.5);

Basically I am trying to check whether a "room" is available for a selected time interval by checking if this interval does not overlap with any existing reservation date intervals ('2018-11-21 12:00','2018-11-23 12:00'),('2018-11-19 12:00','2018-11-20 12:00'). 基本上,我正在尝试通过检查此时间间隔是否与任何现有的预订日期时间间隔不重叠来检查选定时间间隔是否有“房间”('2018-11-21 12:00','2018-11-23 12:00'),('2018-11-19 12:00','2018-11-20 12:00')。 So far I have been successful in checking the first element of the array for each row by writing the following query: 到目前为止,通过编写以下查询,我已经成功地检查了每一行的数组的第一个元素:

SELECT * FROM rooms R 
WHERE R.reservations[1] IS null 
OR NOT (('2018-11-18 12:00','2018-11-20 12:00') 
OVERLAPS (R.reservations[1].checkIn, R.reservations[1].checkOut)) 
ORDER BY rid;

The problem is that I don't know how to check all elements in the array if there is more than one. 问题是,如果有多个元素,我不知道如何检查数组中的所有元素。 Any ideas or suggestions? 有什么想法或建议吗?

You can use unnest to transform array into row on the fly 您可以使用unnest快速将数组转换为行

SELECT * 
  FROM rooms R,
    LATERAL (SELECT bool_or(
                        ('2018-11-18 12:00','2018-11-20 12:00') 
                       OVERLAPS (periods.checkIn, periods.checkOut)
                   ) as someone_overlaps
              FROM unnest(R.reservations) periods
             ) ok
  WHERE someone_overlaps is not true
  ORDER BY rid;

Explain 说明

  1. For each row in this sentence you do a "Lateral" subselect to ask if it overlaps 对于此句子中的每一行,您都进行“横向”子选择以询问其是否重叠
  2. Unnest array into several rows 将数组嵌套成几行
  3. Check the overlaps 检查重叠
  4. Compute the OR of each overlap, take it in the someone_overlapas 计算每个重叠的OR ,将其放入someone_overlapas
  5. List each row that not have someone_overlapas 列出没有someone_overlapas每一行

Notes 笔记

  • Booleans in postgress have three states: true , false and null thats why is not the same not someone_overlaps that someone_overlaps is not true , in the first case the null value remains null in the seconds null is not true . postgress中的布尔值具有三种状态: truefalsenull这就是为什么不一样的原因not someone_overlaps that someone_overlaps is not true ,在第一种情况下null值在几秒钟内仍为null null is not true The second is used because the reservations may be an empty array. 之所以使用第二个,是因为预留可能是一个空数组。
  • Lateral a keyword that allows to use previous tables (in the from list) to be used in the curren subselct Lateral关键字,允许使用当前表(在from列表中)在curren subselct中使用
  • unnest a function that transforms array into row unnest将数组转换为行的函数
  • you can see a living example at: https://dbfiddle.uk/?rdbms=postgres_10&fiddle=c070f0eeaf4206f0540d9187c5e874d3 您可以在以下位置看到一个生动的示例: https//dbfiddle.uk/?rdbms = postgres_10&fiddle = c070f0eeaf4206f0540d9187c5e874d3

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM