Как я могу указать в своей таблице, что у меня не может быть двух одинаковых значений в 3 столбцах с уникальными или другими командами?

У меня есть таблица бронирования, и я хочу убедиться, что у меня нет двух бронирований на один и тот же номер в одном и том же отеле на одну и ту же дату.

Я написал ниже запрос для таблицы.

Create table resevations
(
    hotel_id varchar(10),
    cus_id varchar(10),
    room_id varchar(10),
    date_from date,
    date_to date,
    primary_key(hotel_id,customer_id,date_from),
    unique(hotel_id,room_id,date_from)
)

Я не уверен, что комбинация столбцов в уникальном может это сделать или нет.


person Community    schedule 10.02.2018    source источник
comment
Хотели бы вы изменить дизайн стола? У меня может быть идея, но для этого потребуется изменить структуру вашей таблицы.   -  person Alexis.Rolland    schedule 10.02.2018
comment
Почему бы вам не попробовать написать триггер для этого?   -  person Vijay Rathore    schedule 10.02.2018
comment
То, что у вас есть, допускает чрезмерное бронирование и другие некрасивые ситуации. Наличие только date (вместо date_from и date_to) позволяет легко ограничить ситуацию, но вам нужно несколько строк, чтобы указать резервирование на несколько дней. Какую часть вы хотите облегчить??   -  person Rick James    schedule 11.02.2018


Ответы (2)


Лучше всего обрабатывать проверку вручную. Использование уникальных ключей or не будет работать, поскольку вам нужно подтвердить диапазон дат, а не только дату начала, поэтому бронирование номера с 01.02.2018 по 09.02.2018 не помешает вам забронировать номер с 2018 года. С 03.02 по 07.02.2018 они полностью совпадают, но даты разные.

SELECT 1 FROM resevations
WHERE (({startDate} BETWEEN date_from AND date_to OR {endDate} BETWEEN date_from AND date_to)
OR (date_from BETWEEN {startDate} AND {endDate} OR date_to BETWEEN {startDate} AND {endDate}))
AND hotel_id = {hotelID} AND room_id = {roomID} LIMIT 1

Заполните фигурные скобки резервированием, которое вы пытаетесь сделать, это вернет 1 (true), если оно перекрывает существующее резервирование, или никаких результатов, если оно не перекрывается. После того, как вы это вернули, вы либо ошиблись, либо сохранили бронирование.

Как предложил Пол Шпигель, для этого запроса существует гораздо более простое предложение where, в котором вы просто проверяете, что np бронирований для этой комнаты начинаются до даты окончания и заканчиваются после даты начала, одно из которых должны быть верны для любых перекрывающихся оговорок.

SELECT 1 FROM resevations
WHERE date_from <= {endDate} AND date_to >= {startDate}
AND hotel_id = {hotelID} AND room_id = {roomID} LIMIT 1
person Andrew    schedule 10.02.2018
comment
Вопрос помечен как mysql. Поэтому вы должны использовать LIMIT 1 (в конце оператора) вместо TOP 1. Однако ваш запрос не поможет, если {startDate} и {endDate} оба находятся за пределами диапазона. - person Paul Spiegel; 10.02.2018
comment
@PaulSpiegel Да, это поможет, если оба находятся за пределами диапазона. Если запрос возвращает 1, то создать бронь нельзя, если запрос не возвращает 1, то можно. Я делаю очень похожую вещь с MsSql для проверки своих систем. Вы используете скалярный результат (1 или null), преобразованный в логическое значение в любой системе, обращающейся к базе данных, чтобы определить, существует ли перекрывающееся резервирование. - person Andrew; 10.02.2018
comment
У вас есть строка в БД с (2018-02-05, 2018-02-07). Теперь вы хотите зарезервировать комнату для (2018-02-04, 2018-02-08). Ваш запрос не найдет перекрытия, потому что ни 2018-02-04, ни 2018-02-08 не находятся в диапазоне (2018-02-05, 2018-02-07). - person Paul Spiegel; 10.02.2018
comment
@PaulSpiegel Ааа, теперь я понимаю, что вы имеете в виду, да, вам придется идти в обе стороны. Сделал изменение, чтобы проверить оба пути. - person Andrew; 10.02.2018
comment
Однако - короткий путь date_from <= {endDate} AND date_to >= {startDate}. Но для бронирования гостиничных номеров обычно используются < и >, поскольку вы можете зарегистрироваться в тот же день, когда другой клиент выезжает. - person Paul Spiegel; 10.02.2018

По определению первичный ключ уникален.
Поэтому я думаю, что в вашем случае наличие составного первичного ключа (hotel_id, room_id, cutomer_id, date) должно помочь.
это означает, что резервирование уникально для одного клиента в один отель и один номер в одно и то же время.

надеюсь, это поможет

person Mheni    schedule 10.02.2018
comment
Да, это правильно. Но как вы думаете, я не получу повторяющуюся ошибку, если у меня будет тот же room_id? - person ; 10.02.2018
comment
@ChristianoMoshar Нет, ваш первичный ключ представляет собой комбинацию этих трех столбцов, если все три уникальны, это вызовет ошибку. - person Andrew; 10.02.2018
comment
о, теперь я вижу, я думаю, что это больше связано с дизайном, может быть, вы можете связать комнату с одним клиентом, имея в комнате внешний ключ, ссылающийся на клиента - person Mheni; 10.02.2018
comment
Это будет работать, только если у вас есть одна строка для каждой зарезервированной даты. Но в таблице используется диапазон дат для каждого бронирования. Вы не можете избежать перекрытия диапазона уникальным ограничением. - person Paul Spiegel; 10.02.2018
comment
да, это правильно, я не обратил на это внимание. я думаю, что @Andrew очень хорошо освещает это в своем ответе - person Mheni; 10.02.2018
comment
Этот PK позволяет нескольким клиентам бронировать один и тот же номер на одну и ту же дату — не очень хорошая ситуация. - person Rick James; 11.02.2018