【发布时间】:2013-04-30 14:59:48
【问题描述】:
在 SQL Server 2012 中执行的测试表明,如果即使删除表中的一条记录也会导致外键违规,命令 DELETE FROM dbo.TableName 会停止并返回错误。没有记录被删除。
假设未使用的记录是可以在不违反外键关系的情况下删除的记录。
假设所有记录都可以通过不可为空的整数 ID 列唯一标识。
假设忽略可能导致副作用的功能是安全的,例如触发器或级联删除。
关于表的其他内容,应该假设它的记录和关系。 (例如:解决方案在这些参数内应该是通用的。)
是否存在以以下形式删除未使用的父记录的解决方案:
- SQL 会忽略导致错误的记录,并成功执行没有错误的记录?
- SQL 将只对一组以某种方式检测到的未使用的父记录执行 DELETE? (对于已知 FK 关系的特定表很容易做到。一般不太容易做到。)
- 执行与上述解决方案等效的服务器端代码?
注意事项:
- SQL 解决方案优于需要 C#、Python、Java、Ruby 等的解决方案。
- 跨 RDBMS 解决方案优于 RDBMS 特定解决方案。
请说明您的解决方案适用于并已经过测试的 RDBMS。
【问题讨论】:
-
我不关注此评论:
SQL which will perform a DELETE only upon a set of somehow-detected orphan records? (Easily done for a specific table where the FK relationships are known. Less easily done generically.)我认为根据定义,如果一条记录与外部表中的记录具有某种外键关系,则它只能是孤儿已删除(在这种情况下,基于 OUTER JOIN 选择这些记录总是很容易)。一般地做这件事是什么意思? -
在 Oracle 中,您可以将选项
log errors into与DELETE语句一起使用。跨 dbms 解决方案类似于delete from foo where id in (select ...),其中子选择将返回“孤立”行。 -
Mike Brant:我见过的大多数解决方案都是针对记录/表定义的。您必须知道当前记录的每个父表。 “通用解决方案”将能够检测记录或表的外键关系,并且只删除不会导致外键违规的记录。这与手动指定记录可能与之相关的每个表并执行连接相反。
-
请问为什么?您创建一个 FK 来限制值。为什么需要清除未引用的 FK 值表?如果下一个插入是您清除的值而现在插入失败怎么办?
-
Blam:这个想法实际上是清除不再引用有效外键的记录表。我们正在删除子实体,而不是父实体。这些是孤立的记录,不再属于数据库。如果它们在生产中使用,我们会尝试通过外键找到它们的父实体,但它不会存在。至于为什么会发生这种事情,情况可能会有所不同——从测试数据到不成熟的应用程序,再到 DB 模式更改,再到允许 0..n 关系而不是 1..n 关系的 DB 模式(这可能在架构但不在应用程序中)。
标签: mysql sql sql-server oracle tsql