假设所有外键都有适当的约束,是否有一个简单的SQL语句来删除在数据库中任何地方没有引用的行?SQL删除孤儿
像delete from the_table
那样简单,只需跳过任何带有子记录的行?
我试图避免手动循环表或添加类似where the_SK not in (a,b,c,d)
。
假设所有外键都有适当的约束,是否有一个简单的SQL语句来删除在数据库中任何地方没有引用的行?SQL删除孤儿
像delete from the_table
那样简单,只需跳过任何带有子记录的行?
我试图避免手动循环表或添加类似where the_SK not in (a,b,c,d)
。
您可能能够使用扩展DELETE
声明在10g中包含错误日志。
首先使用DBMS_ERRLOG
创建一个记录表(这仅仅是一个带有一些额外的前缀列原始表的副本:ORA_ERR_MESG$, ..., ORA_ERR_TAG$
)现在
execute dbms_errlog.create_error_log('parent', 'parent_errlog');
,你可以使用delete语句的错误日志条款捕捉那些现有的完整性约束的所有行:
delete from parent
log errors into parent_errlog ('holding-breath')
reject limit unlimited;
在这种情况下,“持有呼气”的评论将进入ORA_ERR_TAG$
列。
您可以阅读完整的文档here。
如果父表非常庞大,而您只希望删除一些流浪行,那么您最终将得到一个parent_errlog
表,它基本上与您的parent
表重复。如果这也不行,你必须做的很长的路要走:
号很明显,你可以这样做(但我知道你宁愿不):
delete parent
where not exists (select null from child1 where child1.parent_id = parent.parent_id)
and not exists (select null from child2 where child2.parent_id = parent.parent_id)
...
and not exists (select null from childn where childn.parent_id = parent.parent_id);
最简单的方法可能是编写一个应用程序或存储过程,该应用程序或存储过程试图一次一个地删除表中的行,并简单地忽略由于外键约束而导致的故障。之后,所有不在外键约束下的行都应该被删除。根据所需/可能的性能,这可能是一个选项。要做到这一点
一种方式是写像下面这样:
eForeign_key_violation EXCEPTION;
PRAGMA EXCEPTION_INIT(eForeign_key_violation, -2292);
FOR aRow IN (SELECT primary_key_field FROM A_TABLE) LOOP
BEGIN
DELETE FROM A_TABLE A
WHERE A.PRIMARY_KEY_FIELD = aRow.PRIMARY_KEY_FIELD;
EXCEPTION
WHEN eForeign_key_violation THEN
NULL; -- ignore the error
END;
END LOOP;
如果一个孩子行存在的DELETE将失败,没有行会被删除,你可以继续你的下一个重点。
请注意,如果您的表格很大,则可能需要很长时间。
不错,我不知道这个错误记录。这样我既不需要指定孩子也不需要遍历行,但我认为你应该添加“拒绝限制无限”(或任何数字)。事实上,删除仍然失败。 – RichN 2010-01-12 07:56:19
斑点 - 添加到我的答案 – 2010-01-12 13:53:45