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

时间:2018-11-18 14:38:04

标签: sql postgresql postgresql-9.6

PostgreSQL(9.6),我正在尝试检查日期间隔

('2018-11-18 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')}

数组中的元素是复合的:

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

这是房间表:

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);

基本上,我正在尝试通过检查此时间间隔是否与任何现有的预订日期时间间隔(“ 2018-11-21 12:00”,“ 2018- 11-23 12:00'),('2018-11-19 12:00','2018-11-20 12:00')。到目前为止,通过编写以下查询,我已经成功地检查了每一行的数组的第一个元素:

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;

问题是,如果有多个元素,我不知道如何检查数组中的所有元素。有什么想法或建议吗?

1 个答案:

答案 0 :(得分:1)

您可以使用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;

说明

  1. 对于此句子中的每一行,您都进行“横向”子选择以询问其是否重叠
  2. 将数组嵌套成几行
  3. 检查重叠部分
  4. 计算每个重叠的OR,将其放入someone_overlapas
  5. 列出没有someone_overlapas的每一行

注释

  • postgress中的布尔值具有三种状态:truefalsenull,这就是为什么not someone_overlapssomeone_overlaps is not true不同的原因,在第一种情况下, null的值在null秒内保持null is not true。之所以使用第二个,是因为预留可能是一个空数组。
  • Lateral一个关键字,该关键字允许使用在curren subselct中使用的先前表(在from列表中)
  • unnest一个将数组转换为行的函数
  • 您可以在以下地方看到一个生动的示例:https://dbfiddle.uk/?rdbms=postgres_10&fiddle=c070f0eeaf4206f0540d9187c5e874d3