删除所有没有外键约束的记录

时间:2010-05-06 23:45:32

标签: sql sql-server foreign-keys constraints rowdeleting

我有一个SQL 2005表,其中包含数百万行,这些行被用户整天瞄准。该表由20个左右的具有外键约束的表引用。我需要定期做的是删除此表中“Active”字段设置为false的所有记录,并且在引用父记录的任何子表中没有其他记录。如果没有尝试一次删除每个错误并让它导致违反约束的SQL错误,那么最有效的方法是什么?此外,它不是禁用约束的选项,并且我不能在任何大量时间内导致父表上的锁定。

3 个答案:

答案 0 :(得分:7)

如果未链接的非活动行不太可能会链接,您可以运行(甚至根据外键元数据动态构建):

SELECT k.*
FROM k WITH(NOLOCK)
WHERE k.Active = 0
AND NOT EXISTS (SELECT * FROM f_1 WITH(NOLOCK) WHERE f_1.fk = k.pk)
AND NOT EXISTS (SELECT * FROM f_2 WITH(NOLOCK) WHERE f_2.fk = k.pk)
...
AND NOT EXISTS (SELECT * FROM f_n WITH(NOLOCK) WHERE f_n.fk = k.pk)

你可以很容易地把它变成DELETE。但是大型删除可能会占用很多锁,因此您可能希望将其放入表中然后批量删除 - 除非记录已链接,否则批处理不应失败。

为了提高效率,您确实需要在相关表格中的FK列上设置索引。

您也可以使用左连接执行此操作,但是您(有时)必须使用DISTINCT或GROUP BY进行重复数据删除,并且执行计划通常不会更好,并且不利于代码生成:

SELECT k.*
FROM k WITH(NOLOCK)
LEFT JOIN f_1 WITH(NOLOCK) ON f_1.fk = k.pk
LEFT JOIN f_2 WITH(NOLOCK) ON f_2.fk = k.pk
...
LEFT JOIN f_n WITH(NOLOCK) ON f_n.fk = k.pk
WHERE k.Active = 0
    AND f_1.fk IS NULL
    AND f_2.fk IS NULL
    ...
    AND f_n.fk IS NULL

答案 1 :(得分:4)

让我们拥有名为Parent的父表,它包含任何类型的“id”字段和Active类型的“bit”字段。我们还有第二个Child表,其中包含自己的“id”字段和“fk”字段,该字段是对{{1}的“id”字段的引用表。然后您可以使用以下语句:

Parent

答案 2 :(得分:0)

对你的问题略感困惑。但是你可以从你的主表中执行一个LeftOuterJoin,到一个应该有一个外键的表。然后,您可以使用Where语句检查连接表中的空值。

点击此处查看外部联接:http://en.wikipedia.org/wiki/Join_%28SQL%29#Left_outer_join

当删除记录或将记录设置为false等时,您还应该编写触发器来为您完成所有这些操作。