postgreSQL - 检查一个日期间隔是否不与每一行的间隔数组中的日期间隔重叠
postgreSQL - Checking if one date interval does not overlap a date interval in array of intervals for each row
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
)
这是房间 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);
基本上,我试图通过检查此间隔是否与任何现有预订日期间隔重叠('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;
问题是如果有多个元素,我不知道如何检查数组中的所有元素。有什么想法或建议吗?
您可以使用 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;
解释
- 对于这句话中的每一行,你做一个"Lateral"子选择来询问它是否重叠
- 将数组取消嵌套成多行
- 检查重叠
- 计算每个重叠的
OR
,将其放入someone_overlapas
- 列出没有
someone_overlapas
的每一行
备注
- postgress 中的布尔值具有三种状态:
true
、false
和 null
这就是为什么 not someone_overlaps
与第一个 someone_overlaps is not true
不同如果 null
值在 null is not true
秒后保持 null
。使用第二个是因为保留可能是一个空数组。
Lateral
一个关键字,允许在当前子选择中使用以前的表(在 from 列表中)
unnest
将数组转换为行的函数
- 您可以在以下位置看到一个活生生的例子:https://dbfiddle.uk/?rdbms=postgres_10&fiddle=c070f0eeaf4206f0540d9187c5e874d3
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
)
这是房间 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);
基本上,我试图通过检查此间隔是否与任何现有预订日期间隔重叠('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;
问题是如果有多个元素,我不知道如何检查数组中的所有元素。有什么想法或建议吗?
您可以使用 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;
解释
- 对于这句话中的每一行,你做一个"Lateral"子选择来询问它是否重叠
- 将数组取消嵌套成多行
- 检查重叠
- 计算每个重叠的
OR
,将其放入someone_overlapas
- 列出没有
someone_overlapas
的每一行
备注
- postgress 中的布尔值具有三种状态:
true
、false
和null
这就是为什么not someone_overlaps
与第一个someone_overlaps is not true
不同如果null
值在null is not true
秒后保持null
。使用第二个是因为保留可能是一个空数组。 Lateral
一个关键字,允许在当前子选择中使用以前的表(在 from 列表中)unnest
将数组转换为行的函数- 您可以在以下位置看到一个活生生的例子:https://dbfiddle.uk/?rdbms=postgres_10&fiddle=c070f0eeaf4206f0540d9187c5e874d3