Один к одному и один ко многим вместе, как проектировать? - PullRequest
2 голосов
/ 02 апреля 2011

У меня есть столик для машины и стол для водителя. Некоторые автомобили могут водить каждый автомобиль, но один из них должен быть активным водителем, и каждый водитель может вести один и только один автомобиль. Мне нужно запросить активного водителя, и мне нужно найти машину, на которой водитель может ездить, даже если он активен или нет. Как мне составить таблицы и ограничения? Я ставлю FK друг другу, но это не правильно.

Ответы [ 2 ]

2 голосов
/ 02 апреля 2011

Для управления этими требованиями я бы предложил использовать соединительную таблицу следующим образом:

Driver > Table
    Id  - pkey
    ... other fields

CarDriver > Junction Table
    DriverId - part 1 composite pkey, foreign key to Driver.Id
    CarId - part 2 composite pkey, foreign key to Car.Id

Car > Table
    Id - pkey
    ActiveDriverId - foreign key to Driver.Id
    ... other fields

Поле CurrentDriverId в таблице Car будет указывать текущего водителя, в то время как таблица соединений CarDriver покажет, какие водители могут управлять какими автомобилями. Обратите внимание, что для сохранения необходимой информации и состояния требуется очень мало полей.

2 голосов
/ 02 апреля 2011

Это сложный способ управления с использованием ограничений базы данных.Вы можете поместить столбец внешнего ключа в таблицу CAR, указывающий на DRIVER, и внешний ключ в DRIVER, указывающий на CAR, но это не гарантирует, что каждый автомобиль и водитель указывают друг на друга.

Исходное предложение:

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

DRIVER_ASSIGNMENT
( car_id int not null
, driver_id int not null 
, start_time datetime not null
, end_time datetime not null
, primary key (car_id, driver_id, start_time)
, unique key (car_id, start_time)
, unique key (driver_id, start_time)
)

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

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

Редактировать 3: Упрощение / разделение проблем:

Пол прокомментировал, что мое первоначальное предложение былосложный из-за смешивания истории с текущим назначением.Я согласен с этим.Это было что-то, что мучило меня после того, как я опубликовал решение.Мне кажется, что лучший подход - это тот, который удовлетворяет требованию ФП о том, чтобы один и тот же автомобиль и один водитель были сопоставлены одновременно - используя только ограничения базы данных и не прибегая к процедурному коду бизнес-правил для обеспечения кардинальности, но в то же времяпредусматривающее требование отслеживать, кто за рулем какого автомобиля и когда.

Поэтому я бы пересмотрел конструкцию, чтобы использовать две отдельные таблицы, например:

DRIVER_ASSIGNMENT
( car_id int not null
, driver_id int not null 
, start_time datetime not null default GETDATE
, primary key (car_id, driver_id)
, unique key (car_id)
, unique key (driver_id)
)

DRIVER_ASSIGNMENT_HISTORY
( car_id int not null
, driver_id int not null 
, start_time datetime not null
, end_date datetime not null  -- This is optional. It is nice to have but not necessary.
, primary key (car_id, driver_id, start_time)
)

С этой схемой водители и автомобили могутбыть в паре друг с другом, но история этих пар отслеживается.Таблица DRIVER_ASSIGNMENT определяет количество элементов, а таблица DRIVER_ASSIGNMENT_HISTORY позволяет видеть, кто за рулем, что и когда.Единственный процедурный код, который вам нужно будет написать, - это код, который принимает каждую вставку или обновление в DRIVER_ASSIGNMENT и создает вставку в DRIVER_ASSIGNMENT_HISTORY.Это может быть создано как триггер базы данных, и в этом случае приложению по-прежнему не требуется процедурный код, и все может быть заключено в аккуратную транзакцию, чтобы все было согласованно.

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