postgreSQL - проверка, не перекрывает ли один интервал дат интервал дат в массиве интервалов для каждой строки - PullRequest
0 голосов
/ 18 ноября 2018

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 голосов
/ 19 ноября 2018

Вы можете использовать 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 имеют три состояния: true, false и null, поэтому это не то же самое not someone_overlaps, что someone_overlaps is not true, в первом случае значение null остается null в секунд null is not true. Второй используется, потому что резервирование может быть пустым массивом.
  • Lateral ключевое слово, которое позволяет использовать предыдущие таблицы (в списке from) для использования в текущем подсекте
  • unnest функция, преобразующая массив в строку
  • Вы можете увидеть живой пример по адресу: https://dbfiddle.uk/?rdbms=postgres_10&fiddle=c070f0eeaf4206f0540d9187c5e874d3
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...