当前位置: 首页 > 知识库问答 >
问题:

如果没有任何其他子级引用,则删除父级

陶飞鸿
2023-03-14

我有一个示例情况:表有一个名为id的列,在表中作为外键引用。

删除子行时,如果父行未被任何其他子行引用,如何删除父行?

共有2个答案

鲁望
2023-03-14
delete from child
where parent_id = 1

在子项中删除后,在父项中删除:

delete from parent
where
    id = 1
    and not exists (
        select 1 from child where parent_id = 1
    )

不存在条件将确保它仅在子级中不存在时才会被删除。您可以将两个删除命令包装在事务中:

begin;
first_delete;
second_delete;
commit;
方楷
2023-03-14

在PostgreSQL 9.1或更高版本中,您可以使用使用数据修改CTE的单个语句来执行此操作。这通常不太容易出错。它最大限度地减少了两个DELETE之间的时间框架,其中竞争条件可能会导致并发操作的惊人结果:

sql prettyprint-override">WITH del_child AS (
    DELETE FROM child
    WHERE  child_id = 1
    RETURNING parent_id, child_id
    )
DELETE FROM parent p
USING  del_child x
WHERE  p.parent_id = x.parent_id
AND    NOT EXISTS (
   SELECT 1
   FROM   child c
   WHERE  c.parent_id = x.parent_id
   AND    c.child_id <> x.child_id   -- !
   );

数据库

在任何情况下都会删除该子项。我引用手册:

with中的数据修改语句只执行一次,并且始终执行到完成,与主查询是否读取其所有(或任何)输出无关。请注意,这与withSELECT的规则不同:如上一节所述,SELECT的执行仅在主查询需要其输出的范围内进行。


注意最后一个条件。与预期相反,这是必要的,因为:

中的子语句与主查询同时执行。因此,当使用<code>中的数据修改语句时,指定更新实际发生的顺序是不可预测的。所有语句都使用相同的快照执行(参见第13章),因此它们无法“看到”彼此对目标表的影响。


我用列名parent_id代替了非描述性的id

为了完全消除上面提到的可能的争用条件,首先锁定父行。当然,所有类似的操作都必须遵循相同的程序才能工作。

WITH lock_parent AS (
   SELECT p.parent_id, c.child_id
   FROM   child  c
   JOIN   parent p ON p.parent_id = c.parent_id
   WHERE  c.child_id = 12              -- provide child_id here once
   FOR    NO KEY UPDATE                -- locks parent row.
   )
 , del_child AS (
   DELETE FROM child c
   USING  lock_parent l
   WHERE  c.child_id = l.child_id
   )
DELETE FROM parent p
USING  lock_parent l
WHERE  p.parent_id = l.parent_id
AND    NOT EXISTS (
   SELECT 1
   FROM   child c
   WHERE  c.parent_id = l.parent_id
   AND    c.child_id <> l.child_id   -- !
   );

这样,一次只有一个事务可以锁定同一个父事务。因此,多个事务删除同一父级的子项,仍然看到其他子项并保留父项,而所有子项之后都消失了,这是不可能的。(对于无密钥更新,仍允许对非密钥列进行更新

如果这种情况从未发生过,或者您可以忍受它(几乎从未发生过)发生——第一个查询更便宜。否则,这是安全路径。

Postgres 9.4中引入了< code>FOR NO KEY UPDATE。手册中有详细说明。在旧版本中,请改用更强的锁< code>FOR UPDATE。

 类似资料:
  • 我尝试了第二个查询的子表的-join,但它没有给出理想的结果。 我的第一个查询工作良好,我得到了正确的父列表,我的问题是没有得到所有的孩子当我运行第二个查询。如何解决这个问题?

  • 本文向大家介绍如何使用jQuery从父级删除所有子级节点?,包括了如何使用jQuery从父级删除所有子级节点?的使用技巧和注意事项,需要的朋友参考一下 要从父级删除所有子节点,请使用方法。该方法从匹配的元素集中删除所有子节点。 示例 您可以尝试运行以下代码以了解如何从父级删除所有子节点-

  • 问题内容: 假设我们有3个Entities对象类: 如何使用JPA2.x(或hibernate)批注来: 父级删除时(一对多)自动删除所有子级 删除后自动从子级列表中删除子级(多对一) 儿童删除时(一对一)自动删除玩具 我正在使用Hibernate 4.3.5和mysql 5.1.30。 谢谢 问题答案: 如本文所述, 实体状态转换应从父级到子级联,而不是相反。 您需要这样的东西:

  • 问题内容: 我要删除,因此要从数据库中删除行。 我 确实 要删除某个实体及其所有行。不过,我 不 希望从它删除任何行。 如何 我能做到这一点? 是,并且是我要删除的实体。 请参阅下面的代码,了解我如何在“狗窝实体”中链接2: 目前,当我删除狗entitie(S),其相关的养犬实体 中 也被删除。 编辑:将狗映射到狗窝: 问题答案: 当前,当我删除狗实体时,其相关的狗窝实体也将被删除。 原因是您已设

  • 我有两个实体使用Spring和Hibernate

  • 我试图递归删除JSON对象和所有子对象中的空值。如果子对象的关键点都已删除,则我希望该子对象也被删除。 比如。 应该变成这样: 下面是我编写的删除所有空值键的函数: 但这不会删除没有子项的父项: 因此,我得到的不是上面的结果,而是: 如您所见,它不会删除申请人的密钥。我如何在函数中检查它?或者它是否需要编写在我调用delKeys()后调用的单独函数中? 还有,有人看到这达到了最大递归深度吗?我尝试