0

我有 2 张桌子:1. 员工 2. 凭证

雇员表有一个主键。Vouchers 表有 3 个引用Employees 表的外键约束。

以下是用于在 SQL Server 中创建两个表及其关系的示例 T-SQL 脚本(不是实际的表脚本):

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.

我不知道这里有什么有效的解决方案。对关系的要求是:每当删除 Employee 时,将其某些列引用到 Employee 的 Voucher 不会被删除(ON DELETE CASCADE 不是一个选项)。相反,引用到已删除员工的列(IssuedBy、ReceivedBy 和/或 ApprovedBy)的值应设置为 NULL(因为这些列是 NULLABLE)。

非常感谢!

4

3 回答 3

3

严格从关系设计的角度来看,Vouchers 表是三个外键。无论您选择通过 CASCADE 断言还是其他方式强制执行它们,都是一个实现问题,但关系设计仍然存在。假设您想要强制执行,如果三个字段之一不为 NULL,则需要存在匹配记录。或不。关于您是否关心强制执行设计是一个实现问题。

但是,您描述的违规行为将由您承担风险。你问这个问题的事实表明你可能没有完全理解这些选择可能导致沼泽的所有方式。

我认为该错误可能是由于三者中不止一个可能指的是同一员工。

顺便说一句,在极少数情况下,我发现有必要以 CASCDES 有用的方式删除记录。通常这将用于防止数据库太大;随着时间的推移,数据库容量的问题越来越少。

于 2009-01-11T03:55:59.940 回答
2

我实际上不会删除员工,而是使用触发器设置一个标志以将它们标记为已删除。

我通常不打开更新或删除的级联,而是要求应用程序显式执行这些操作。

于 2009-01-11T04:10:18.413 回答
1

从设计的角度来看,拥有您列出的 3 个外键似乎很好。看起来您收到的错误消息与外键上的 ON UPDATE CASCADE 选项有关(尽管我能够按指定创建表)。无论如何,为了获得您提到的想要的行为,我建议在员工表上使用一个触发器,该触发器在您删除记录之前触发。此触发器将在 Vouchers 表中找到Employees.OjbectID 的实例并将它们设置为NULL。

于 2009-01-11T04:03:15.743 回答