Это сложный способ управления с использованием ограничений базы данных.Вы можете поместить столбец внешнего ключа в таблицу 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.Это может быть создано как триггер базы данных, и в этом случае приложению по-прежнему не требуется процедурный код, и все может быть заключено в аккуратную транзакцию, чтобы все было согласованно.