SQL 删除孤儿

发布于 2024-08-17 08:04:27 字数 194 浏览 4 评论 0原文

假设所有外键都有适当的约束,是否有一个简单的 SQL 语句来删除数据库中任何地方未引用的行?

delete from the_table 这样简单的事情,只需跳过带有子记录的任何行?

我试图避免手动循环表格或添加类似 where the_SK not in (a,b,c,d) 的内容。

Assuming that all foreign keys have the appropriate constraint, is there a simple SQL statement to delete rows not referenced anywhere in the DB?

Something as simple as delete from the_table that simply skip any rows with child record?

I'm trying to avoid manually looping through the table or adding something like where the_SK not in (a,b,c,d).

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

装迷糊 2024-08-24 08:04:27

您也许可以使用 10g 中包含错误日志记录的扩展 DELETE 语句。

首先使用 DBMS_ERRLOG 创建一个日志表(它只是原始表的副本,带有一些附加前缀列:ORA_ERR_MESG$, ..., ORA_ERR_TAG$

execute dbms_errlog.create_error_log('parent', 'parent_errlog');

现在,您可以使用删除语句的 LOG ERRORS 子句来捕获具有现有完整性约束的所有行:

delete from parent
   log errors into parent_errlog ('holding-breath')
   reject limit unlimited;

在这种情况下,“holding-breath”注释将进入 ORA_ERR_TAG$ 列。

您可以在此处阅读完整文档

如果父表很大并且您只想删除一些杂散行,那么您最终会得到一个 parent_errlog 表,该表本质上是您的父表的副本桌子。如果这不行,您将不得不做很长的路:

  1. 直接引用子表(遵循托尼的解决方案),或者,
  2. 循环遍历 PL/SQL 中的表并捕获任何异常(遵循混乱鲍勃的解决方案)。

You might be able to use the extended DELETE statement in 10g that includes error logging.

First use DBMS_ERRLOG to create a logging table (which is just a copy of the original table with some additional prefixing columns: ORA_ERR_MESG$, ..., ORA_ERR_TAG$)

execute dbms_errlog.create_error_log('parent', 'parent_errlog');

Now, you can use the LOG ERRORS clause of the delete statement to capture all rows that have existing integrity constraints:

delete from parent
   log errors into parent_errlog ('holding-breath')
   reject limit unlimited;

In this case the "holding-breath" comment will go into the ORA_ERR_TAG$ column.

You can read the full documentation here.

If the parent table is huge and you're only looking to delete a few stray rows, you'll end up with a parent_errlog table that is essentially a duplicate of your parent table. If this isn't ok, you'll have to do it the long way:

  1. Directly reference the child tables (following Tony's solution), or,
  2. Loop through the table in PL/SQL and catch any exceptions (following Confusion's and Bob's solutions).
回忆凄美了谁 2024-08-24 08:04:27

最简单的方法可能是编写一个应用程序或存储过程,尝试逐一删除表中的行,并简单地忽略由于外键约束而导致的失败。然后,所有不受外键约束的行都应该被删除。根据所需/可能的性能,这可能是一种选择。

The easiest way may be to write an application or stored procedure that attempts to delete the rows in the table one-by-one and simply ignores the failures due to foreign key constraints. Afterwards, all rows not under a foreign key constraint should be removed. Depending on the required/possible performance, this may be an option.

赤濁 2024-08-24 08:04:27

不,显然你可以这样做(但我意识到你宁愿不这样做):

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

No. Obviously you can do this (but I realise you would rather not):

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);
小红帽 2024-08-24 08:04:27

一种方法是编写如下内容:

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 将失败,并且不会删除任何行,并且您可以继续处理下一个键。

请注意,如果您的表很大,这可能需要相当长的时间。

One way to do this is to write something like the following:

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;

If a child row exists the DELETE will fail and no rows will be deleted, and you can proceed to your next key.

Note that if your table is large this may take quite a while.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文