Как проверить ограничения между двумя таблицами при вставке в третью таблицу, которая ссылается на две другие таблицы? - PullRequest
3 голосов
/ 31 января 2009

Рассмотрим пример схемы:

Customer ( int CustomerId pk, .... )

Employee ( int EmployeeId pk,
           int CustomerId references Customer.CustomerId, .... )

WorkItem ( int WorkItemId pk,
           int CustomerId references Customer.CustomerId,
           null int EmployeeId references Employee.EmployeeId, .... )

В основном три таблицы:

  • Таблица клиентов с первичным ключом и некоторыми дополнительными столбцами
  • Таблица сотрудников с первичным ключом, ссылка ограничения внешнего ключа на первичный ключ таблиц клиента, представляющая сотрудника клиента.
  • Таблица рабочих элементов, в которой хранится работа, выполненная для клиента, а также информация о конкретном сотруднике, для которого была выполнена работа.

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

Если, например, Скотт (сотрудник) работает в Microsoft (клиент), а Джефф (сотрудник) работает в StackOverflow (клиент), как я могу запретить кому-либо добавлять рабочий элемент в базу данных, когда клиент = Microsoft и сотрудник = Джефф, что не имеет смысла?

Могу ли я сделать это с проверочными ограничениями или внешними ключами или мне нужен триггер, чтобы проверить его вручную?

Следует упомянуть, что я использую SQL Server 2008.

ОБНОВЛЕНИЕ: Я должен добавить, что WorkItem.EmployeeId может быть нулевым.

Спасибо, Эгиль.

Ответы [ 6 ]

3 голосов
/ 31 января 2009

Не будет работать внешний ключ в составном столбце (CustomerId, EmployeeId)?

ALTER TABLE WorkItem
ADD CONSTRAINT FK_Customer_Employee FOREIGN KEY (CustomerId, EmployeeId)
    REFERENCES Employee (CustomerId, EmployeeId);
2 голосов
/ 31 января 2009

Вы можете сделать это, создав представление «WITH SCHEMABINDING», которое охватывает эти таблицы и применяет коллективные ограничения отдельных таблиц.

1 голос
/ 14 октября 2011

Я недавно перешел к аналогичной ситуации, рассмотрим схему: Таблица компании (id_cia PK) Таблица product_group (id_cia FK для компании, id_group PK) Таблица products (id_group FK для product_group, id_product PK, id_used_by_the_client null)

Правило: база данных должна разрешать только один id_used_by_the_client для каждого продукта компании, но это поле может быть нулевым. Пример:

Вставить в компанию (1) = разрешено

Включить в компанию (2) = разрешено

Вставить в группу товаров (1, 1) = разрешено

Вставить в группу товаров (1,2) = разрешено

Вставить в группу товаров (2,3) = разрешено

Вставить в товары значения (1, 1, ноль) = разрешено

Вставить в товары значения (1, 2, ноль) = разрешено

Вставить в товары значения (1, 3, 1) = разрешено

Вставить в товары значения (1, 4, 1) = не разрешено, в группе 1, принадлежащей компании 1, уже существует id_used_by_the_client = 1.

Вставить в товары значения (2, 4, 1) = не разрешено, в группе 2, принадлежащей компании 1, уже существует id_used_by_the_client = 1.

Вставить в товары значения (3, 4, 1) = разрешено, в группе 3, принадлежащей компании 2, нет id_used_by_the_client = 1.

Я решил использовать триггер для контроля этой целостности.

1 голос
/ 31 января 2009

Что вы пытаетесь смоделировать здесь?

  1. Вы - подрядное агентство или подобное, и у вас есть группа подрядчиков, которые (на определенный период времени) назначены клиенту.

  2. На самом деле вы храните информацию о сотрудниках другой компании (например, вы предоставляете услуги по оплате труда сторонних организаций).

В случае (1) похоже, что у вас проблема с таблицей Employee. В частности, когда контракт Скотта с MS истек, и он заключил контракт с кем-то еще, вы не можете хранить исторические данные, потому что вам нужно изменить CustomerId. Что также делает недействительными все WorkItem s. Вместо этого у вас должна быть четвертая таблица, например, CustomerEmployee для ее хранения. Тогда WorkItem должен ссылаться на эту таблицу.

В случае (2) ваш первичный ключ в Employee должен быть действительно CustomerId, EmployeeId. Два клиента могут иметь одинаковый идентификационный номер сотрудника. Тогда сработает внешний ключ Киерона.

1 голос
/ 31 января 2009

Почему вы хотите, чтобы employeeId был нулевым в WorkItem? Может быть, вам следует добавить еще одну таблицу, чтобы избежать этой странности. Из того, что я вижу, проще всего добавить уникальное ограничение employeeid в workItem и, возможно, даже уникальное для customerId, если вы этого хотите.

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

0 голосов
/ 31 января 2009

Либо:

  • сделать столбец EmployeeID Первичным ключом Employee (и, возможно, автоматическим идентификатором) и сохранить EmployeeID в записи WorkItem в качестве внешнего ключа вместо сохранения идентификаторов Employee и Customer в WorkItem. Вы можете получить сведения о клиенте WorkItem, присоединившись к таблице Customer через таблицу Employee.

Или:

  • делает столбцы EmployeeID и CustomerID WorkItem составным внешним ключом для Employee.

Лично я предпочитаю первый подход.

...