Моделирование данных: что такое хороший реляционный дизайн, когда таблица имеет несколько внешних ключей, ограниченных одной таблицей? - PullRequest
0 голосов
/ 11 января 2009

У меня есть 2 таблицы: 1. Сотрудники 2. Ваучеры

Таблица сотрудников имеет один первичный ключ. Таблица ваучеров имеет 3 ограничения внешнего ключа, ссылающиеся на таблицу Employees.

Ниже приведен пример сценария T-SQL (не фактического сценария таблицы) для создания обеих таблиц и их взаимосвязей в SQL Server:

IF OBJECT_ID('dbo.Vouchers') IS NOT NULL
    DROP TABLE dbo.Vouchers
IF OBJECT_ID('dbo.Employees') IS NOT NULL
    DROP TABLE dbo.Employees
GO

CREATE TABLE Employees
(
  ObjectID     INT    NOT NULL   PRIMARY KEY    IDENTITY
)

CREATE TABLE Vouchers
(
  ObjectID     INT    NOT NULL   PRIMARY KEY    IDENTITY,
  IssuedBy     INT,
  ReceivedBy   INT,
  ApprovedBy   INT,

  CONSTRAINT fk_Vouchers_Employees_IssuedBy FOREIGN KEY (IssuedBy)
                                    REFERENCES Employees (ObjectID)
                                    ON UPDATE CASCADE
                                    ON DELETE NO ACTION,
 CONSTRAINT fk_Vouchers_Employees_ReceivedBy FOREIGN KEY (ReceivedBy)
                                    REFERENCES Employees (ObjectID)
                                    ON UPDATE CASCADE
                                    ON DELETE NO ACTION,
 CONSTRAINT fk_Vouchers_Employees_ApprovedBy FOREIGN KEY (ApprovedBy)
                                    REFERENCES Employees (ObjectID)
                                    ON UPDATE CASCADE
                                    ON DELETE NO ACTION 
)

Но выдается ошибка:

Msg 1785, Level 16, State 0, Line 7
Introducing FOREIGN KEY constraint 'fk_Vouchers_Employees_ReceivedBy' on table 'Vouchers' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints.

Я не представляю, какое эффективное решение доступно здесь. Требования к отношениям таковы: при каждом удалении сотрудника ваучер, который ссылается на некоторых его столбцов для сотрудника, не удаляется (ON DELETE CASCADE не вариант). Вместо этого значения столбцов (IssuedBy, ReceivedBy и / или ApprovedBy), на которые ссылается удаленный сотрудник, должны быть установлены в NULL (поскольку столбцы имеют значение NULLABLE).

Большое спасибо!

Ответы [ 3 ]

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

Строго говоря, с точки зрения реляционного проектирования, таблица ваучеров представляет собой три внешних ключа. Независимо от того, выберете ли вы их принудительное выполнение с помощью утверждений CASCADE или иным образом, это проблема реализации, но реляционный дизайн все еще существует. Предположительно, вы хотите применить это, если одно из трех полей не равно NULL, то соответствующая запись должна существовать. Или нет. Это вопрос реализации того, хотите ли вы обеспечить реализацию проекта.

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

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

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

2 голосов
/ 11 января 2009

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

Обычно я не включаю каскад обновлений или удалений, а вместо этого требую, чтобы приложение явно выполняло эти действия.

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

С точки зрения дизайна кажется хорошим иметь 3 внешних ключа, которые вы перечислили. Похоже, что сообщение об ошибке, которое вы получаете, относится к параметрам ON UPDATE CASCADE ваших внешних ключей (хотя я смог создать таблицу, как указано). Независимо от того, чтобы получить желаемое поведение, я бы порекомендовал триггер для таблицы «Сотрудники», который срабатывает перед удалением записи. Этот триггер найдет экземпляры Employees.OjbectID в таблице Vouchers и установит их в NULL.

...