以什么顺序处理DELETE CASCADE约束?

时间:2020-03-05 18:52:36  来源:igfitidea点击:

这是我正在进行的事情的一个示例:

CREATE TABLE Parent (id BIGINT NOT NULL,
  PRIMARY KEY (id)) ENGINE=InnoDB;

CREATE TABLE Child (id BIGINT NOT NULL,
  parentid BIGINT NOT NULL,
  PRIMARY KEY (id),
  KEY (parentid),
  CONSTRAINT fk_parent FOREIGN KEY (parentid) REFERENCES Parent (id) ON DELETE CASCADE) ENGINE=InnoDB;

CREATE TABLE Uncle (id BIGINT NOT NULL,
  parentid BIGINT NOT NULL,
  childid BIGINT NOT NULL,
  PRIMARY KEY (id),
  KEY (parentid),
  KEY (childid),
  CONSTRAINT fk_parent_u FOREIGN KEY (parentid) REFERENCES Parent (id) ON DELETE CASCADE,
  CONSTRAINT fk_child FOREIGN KEY (childid) REFERENCES Child (id)) ENGINE=InnoDB;

注意,Uncle-Child关系没有ON DELETE CASCADE;即删除孩子不会删除其叔叔,反之亦然。

当我有一个父母和一个带相同孩子的叔叔,并且删除了父母时,似乎InnoDB应该能够"弄清楚它"并让整个家庭中的级联不断波动(即删除父母会删除叔叔)以及儿童)。但是,我得到以下信息:

ERROR 1451 (23000): Cannot delete or update a parent row: a foreign key constraint fails (`cascade_test/uncle`, CONSTRAINT `fk_child` FOREIGN KEY (`childid`) REFERENCES `child` (`id`))

InnoDB试图在引用该子级的Uncle之前级联删除该子级。

我想念什么吗?是否应该由于某种我不理解的原因而失败?还是有一些使它起作用的技巧(或者它是MySQL中的错误)?

解决方案

回答

在较简单的情况下,如果从Child中删除一条记录,并且该记录具有引用的Uncle会发生什么?这是未指定的,因此约束仍然会失败。

如果删除孩子没有删除其叔叔,那么会发生什么呢? Uncle.childid不能为null。

我们想要的是以下三件事之一:

  • Uncle.childid可以为null,并且我们要为childid设置ON DELETE SET NULL。
  • Uncle.childid不能为null,并且我们希望ON DELETE CASCADE作为childid。
  • Childid不属于叔叔,并且我们想要一个ChildsUncle关系,并具有对Child和Uncle的ON DELETE CASCADE外键约束。 Uncleid将是该关系的候选键(即,它应该是唯一的)。

回答

设计全错了。我们应该具有单个表,并且具有父子关系(从字面上看)。
然后,我们可以通过查询找出叔叔(和姨妈)

从以下人群中选择ID:-查找祖父母的所有子女 ( 从人中选择父母-寻找祖父母 在( 从人中选择父母-寻找父母 其中id = THECHILD) ) 减号-带走孩子的父母 从人中选择父母 其中id = THECHILD

回答

如我们所述,父级删除操作会触发子级删除操作,但我不知道为什么它会在叔叔表之前进入子级表。我想我们肯定需要查看dbms代码才能知道,但是我肯定有一种算法可以选择首先层叠哪些表。

该系统并没有真正按照我们在此处暗示的方式"弄清楚"这些内容,它只是遵循其约束规则。问题在于我们创建的架构遇到了不允许其进一步传递的约束。

我明白你在说什么..如果它先打到叔叔表上,它将删除记录,然后删除子级(而不是从子级删除中打到叔叔级联)。但是即使如此,我也不认为会建立一个架构来依赖现实中的这种行为。我认为唯一可以确定发生什么情况的方法是浏览代码或者在这里找一个mysql / postgresql程序员来说它如何处理fk约束。