问题描述
如何通过 FK 删除一个表中没有被其他表中的任何记录引用的记录?
我使用的是 sql Server 2014。示例:
CREATE TABLE Persons (
PersonID int NOT NULL PRIMARY KEY,PersonName varchar(20) NOT NULL);
INSERT INTO Persons VALUES (1,'Alistair'),(2,'Bob'),(3,'Cecile')
CREATE TABLE Orders (
OrderID INT IDENTITY(1,1) NOT NULL PRIMARY KEY,PersonID int FOREIGN KEY REFERENCES Persons(PersonID));
INSERT INTO Orders values (1),(1),(3)
DELETE FROM Persons //-->The DELETE statement conflicted with the REFERENCE constraint FK__Orders__PersonID...
我只想从 Persons 中删除 Bob(因为没有属于他的订单)并保留 Alistair 和 Cecile(并且没有错误当然是留言)。
动机:我需要这个用于删除过时或不需要的记录的维护工作。我能想到的解决方案DELETE FROM Persons WHERE NOT EXISTS(SELECT 1 FROM Orders WHERE Orders.PersonID = Persons.PersonID)
不是很好,因为在我的真实数据库中有很多表和 FK,而且如果有人引入另一个 FK,我的代码就会中断。所以寻找更通用的解决方案。
更新:只是为了扩展为什么我正在寻找除 DELETE ... WHERE NOT EXISTS
之外的其他解决方案的原因是我的数据库中有多个表,我需要在 WHERE 子句中手动列出所有这些表,例如 DELETE ... WHERE NOT EXISTS(...Table1...) AND NOT EXISTS(...Table2...) ... AND NOT EXISTS(...TableN...)
如果开发人员添加了 TableN+1
,我的代码也需要更改。
所以我希望有一些 sql 命令/选项可以做我想要的:只删除不冲突的记录,而不需要手动列出 sql 引擎已经知道的所有约束。
解决方法
一种方法是使用 EXISTS
:
DELETE P
FROM Persons P
WHERE NOT EXISTS(SELECT 1
FROM dbo.Orders O
WHERE O.PersonID = P.PersonID);
另一种方法是使用 LEFT JOIN
:
DELETE P
FROM Persons P
LEFT JOIN dbo.Orders O ON P.PersonID = O.PersonID
WHERE O.OrderID IS NULL;