Question

  • I do not want the orders to be deleted when a customer is deleted. (On Delete Cascade)
  • I use identity columns so I do not need On Update Cascade
  • It should be possible to delete a customer table although there exist orders pointing/referencing to a customer. I do not care when the customer is gone because I still need the order table for other tables.

Does a foreign key make sense in this scenario when I do not use Referential Integrity with On Delete/Update Cascade ?

Was it helpful?

Solution

Yes. The foreign key is not in place only to clean up after yourself but primarily to make sure the data is right in the first place (it can also assist the optimizer in some cases). I use foreign keys all over the place but I have yet to find a need to implement on cascade actions. I do understand the purpose of cascade but I've always found it better to control those processes myself.

EDIT even though I tried to explain already that you can work around the cascade issue (thus still satisfying your third condition), I thought I would add an illustration:

You can certainly still allow for orders to remain after you've deleted a customer. The key is to make the Orders.CustomerID column nullable, e.g.

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));

Now when you want to delete a customer, assuming you control these operations via a stored procedure, you can do it this way, first setting their Orders.CustomerID to NULL:

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

If you can't control ad hoc deletes from the Customers table, then you can still achieve this with an instead of trigger:

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

That all said, I'm not sure I understand the purpose of deleting a customer and keeping their orders (or any indication at all about who placed that order).

OTHER TIPS

So to be clear you have a FK from Customer to Orders presently. Cascade update/delete is not enabled on this relationship. Your plan is to delete customers but allow the orders to remain.

This would VIOLATE the foreign key constraint; and prevent the delete from occurring. If you disable the constraint execute the delete then re-enable you could make it work.

However, this will leave orphaned order records in the system; which might make it harder to support in the long run. What's the next guy who has to support this going to think?

Wouldn't it be better to keep the records and add a status for Active/inactive or created and inactive dates?

I'm struggling with violating the integrity of the database to reduce space...? Or what's the main reason to remove?

If you don't want to have to always filter out the no longer active records use a view or a package which creates a collection of active customers. Eliminating some but not all data seems just wrong to me.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top