Моделирование отношения 1 к 1..n в базе данных - PullRequest
3 голосов
/ 27 октября 2008

Как бы вы смоделировали отношения забронированных гостиничных номеров с гостями (в PostgreSQL, если это важно)? В комнате может быть несколько гостей, но не менее одного.

Конечно, можно отнести гостей к бронированию с иностранным ключом booking_id. Но как обеспечить на уровне СУБД, что в комнате должен быть хотя бы один гость?

Может быть, это просто невозможно?

Ответы [ 6 ]

5 голосов
/ 27 октября 2008

На самом деле, если вы читаете вопрос, в нем говорится о забронированных гостиничных номерах. Это довольно легко сделать следующим образом:

Rooms:
    room_id primary key not null
    blah
    blah

Guests:
    guest_id primary key not null
    yada
    yada

BookedRooms:
    room_id primary key foreign key (Rooms:room_id)
    primary_guest_id foreign key (Guests:guest_id)

OtherGuestsInRooms:
    room_id foreign key (BookedRooms:room_id)
    guest_id foreign key (Guests:guest_id)

Таким образом, вы можете принудительно забронировать забронированную комнату, в которой есть хотя бы один гость, в то время как у других гестов отношение 0 или более. Вы не можете создать забронированный номер без гостя и не можете добавить других гостей без забронированного номера.

Это та же логика, которой вы следуете, если хотите, чтобы отношение n-to-n было нормализовано для отдельной таблицы, содержащей 1-to-n и n-to-1 с двумя таблицами. 1006 *

4 голосов
/ 27 октября 2008

В этом контексте я полагаю, что объект, который вы моделируете, на самом деле является БРОНИРОВАНИЕМ - отдельным объектом, а не двумя объектами комнаты и гостя.

Так что стол будет что-то вроде

BOOKING
-------
booking id
room id
guest id (FK to table of guests for booking)
first date of occupancy
last date of occupancy

Где идентификатор гостя не обнуляется, и у вас есть другой стол для размещения гостей за бронирование ...

GUESTS
------
guest id
customer id (FK to customer table)
1 голос
/ 27 октября 2008

Я думаю, что вы имеете в виду, что номер БРОНИРОВАНИЕ предназначен как минимум для одного гостя. Стандарт SQL ANSI позволит вам выразить ограничение как ASSERTION что-то вроде:

create assertion x as check
   (not exists (select * from booking b
                where not exists
                   (select * from booking_guest bg
                    where bg.booking_id = b.booking_id)));

Однако я не думаю, что Postgres поддерживает это (я не уверен, что какая-либо текущая СУБД поддерживает).

Существует способ использования материализованных представлений и проверки ограничений, но я никогда не видел, чтобы это делалось на практике:

1) Создать материализованное представление как

select booking_id from booking b
where not exists 
   (select * from booking_guest bg 
    where bg.booking_id = b.booking_id);

2) Добавить проверочное ограничение к материализованному представлению:

check (boooking_id is null)

Это ограничение не будет выполнено, если когда-либо материализованное представление не будет пустым, то есть, если будет бронирование без связанного гостя. Однако вам следует быть осторожным с эффективностью этого подхода.

1 голос
/ 27 октября 2008

Вы можете назначить одного из гостей «основным» гостем и сделать так, чтобы он отображался в столбце таблицы «Комнаты». Конечно, это нелепое правило для отеля, где вполне допустимо иметь номер с 0 гостями (я очень хорошо мог бы заплатить за номер и не остаться там) ...

0 голосов
/ 15 сентября 2010

Я бы сказал, что вы должны создать таблицу bookings с тремя первичными ключами. Но вместо того, чтобы ссылаться на бронирование номеров, вы можете обратиться к таблице beds.

bookings:
  bed_id: foreign_key primary
  guest_id: foreign_key primary
  day: date primary
  bill_id: foreign_key not null

beds:
  room_id: foreign_key primary

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

Обратите внимание, что есть только одно поле day. Это требует, чтобы вы создавали бронирование на каждый день пребывания гостя в номере, а также гарантировали, что ничего не будет случайно заказано дважды. Кровать может быть забронирована только одним клиентом в любой день (что не относится к комнатам)

bill_id существует для того, чтобы вы могли отнести бронирование к определенной записи для счета, на которую также могут ссылаться другие вещи, такие как расходы на мини-бар.

0 голосов
/ 27 октября 2008

А как насчет комнаты, которая не была сдана в аренду? То, что вы ищете, - это бронирование, и для бронирования, по-видимому, нужен хотя бы один гость.

Я думаю, что вы спрашиваете, можете ли вы гарантировать, что запись о бронировании не будет добавлена, если у вас нет хотя бы одного гостя, и вы не можете добавить гостя без бронирования. Это что-то вроде Catch-22 для большинства систем СУБД.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...