1
  • 我不希望在删除客户时删除订单。(关于删除级联)
  • 我使用标识列,因此不需要 On Update Cascade
  • 尽管存在指向/引用客户的订单,但应该可以删除客户表。我不在乎客户何时离开,因为我仍然需要其他表的订单表。

当我不将引用完整性与 On Delete/Update Cascade 一起使用时,外键在这种情况下是否有意义?

4

2 回答 2

4

是的。外键不仅是为了自己清理,而且主要是为了首先确保数据是正确的(在某些情况下它也可以帮助优化器)。我到处都使用外键,但我还没有找到实现级联动作的需要。我确实理解级联的目的,但我总是发现自己控制这些过程更好。

编辑即使我已经尝试解释你可以解决级联问题(因此仍然满足你的第三个条件),我想我会添加一个插图:

在删除客户后,您当然仍然可以保留订单。关键是使Orders.CustomerID列可以为空,例如

CREATE TABLE dbo.Customers(CustomerID INT PRIMARY KEY);

CREATE TABLE dbo.Orders(OrderID INT PRIMARY KEY, CustomerID INT NULL
    FOREIGN KEY REFERENCES dbo.Customers(CustomerID));

现在,当您要删除客户时,假设您通过存储过程控制这些操作,您可以这样做,首先将它们设置Orders.CustomerIDNULL

CREATE PROCEDURE dbo.Customer_Delete
  @CustomerID INT
AS
BEGIN
  SET NOCOUNT ON;

  UPDATE dbo.Orders SET CustomerID = NULL
    WHERE CustomerID = @CustomerID;

  DELETE dbo.Customers
    WHERE CustomerID = @CustomerID;
END
GO

如果您无法控制客户表中的临时删除,那么您仍然可以使用而不是触发器来实现此目的:

CREATE TRIGGER dbo.Cascade_CustomerDelete
ON dbo.Customers
INSTEAD OF DELETE
AS
BEGIN
  SET NOCOUNT ON;

  UPDATE o SET CustomerID = NULL
    FROM dbo.Orders AS o
    INNER JOIN deleted AS d
    ON o.CustomerID = d.CustomerID;

  DELETE c
    FROM dbo.Customers AS c
    INNER JOIN deleted AS d
    ON c.CustomerID = d.CustomerID;
END
GO

总而言之,我不确定我是否理解删除客户并保留他们的订单的目的(或任何关于谁下订单的指示)。

于 2012-06-10T18:21:14.977 回答
0

所以要清楚你现在有一个从客户到订单的 FK。此关系未启用级联更新/删除。您的计划是删除客户但保留订单。

这将违反外键约束;并防止删除发生。如果您禁用约束执行删除然后重新启用您可以使其工作。

但是,这会在系统中留下孤立的订单记录;从长远来看,这可能会使支持变得更加困难。下一个必须支持这一点的人会怎么想?

保留记录并为活动/非活动或创建和非活动日期添加状态不是更好吗?

我正在努力破坏数据库的完整性以减少空间......?或者删除的主要原因是什么?

如果您不想总是过滤掉不再活动的记录,请使用创建活动客户集合的视图或包。消除一些但不是所有的数据对我来说似乎是错误的。

于 2012-06-10T18:30:37.537 回答