MySQL:奇怪的外键约束

时间:2014-02-12 12:13:42

标签: mysql constraints

我有两张桌子:

tree_instance:
  - tree_id INT
  - country_id INT
  - time_segment date

node_instance:
  - country_id INT
  - time_segment date
  - CONSTRAINT `node_instance_ibfk_1` FOREIGN KEY (`time_segment`) REFERENCES `tree_instance` (`time_segment`) ON DELETE NO ACTION ON UPDATE NO ACTION

一些事实:

  • 特定国家/地区存在一些节点(节点在国家/地区独立存在)
  • 对于每个国家/地区,可能会有一些树构建一些节点(在同一个国家/地区内)
  • 节点没有tree_id列,因为它们可以包含在0..n树中(对于tree_id列,还有另一个m:n表)
  • 节点可以在同一个国家/地区的不同树之间共享,但不能在不同国家/地区之间共享

当我添加新结构时,首先我添加新的tree_instance,例如

tree_id: 2
country_id: 1
time_segment: 2014-01-01

然后我插入节点。 country_id = 2也是如此。

当我想删除其中一个国家/地区的树时,会出现问题。首先,我尝试删除country_id = 1的所有node_instances。成功。然后我尝试删除tree_instance WHERE country_id = 1,我得到以下错误:

Cannot delete or update a parent row: a foreign key constraint fails (`db_name`.`node_instance`, CONSTRAINT `node_instance_ibfk_1` FOREIGN KEY (`time_segment`) REFERENCES `tree_instance` (`time_segment`) ON DELETE NO ACTION ON UPDATE NO ACTION)

这是因为来自country_id = 2的node_instances指向我要删除的time_segment(约束)。但我无法理解的是,仍然存在一个tree_instance(country_id = 1,我没有删除),其中time_segment可以保存约束。为什么MySQL会抛出约束违规?

3 个答案:

答案 0 :(得分:0)

如果我正确理解了这个问题,那么这就是你要做的事情

  1. node_instance列上的time_segment(子表)中有一个外键,引用tree_instance.time_segment
  2. 您从node_instance的{​​{1}}(子表)中删除记录。此操作成功
  3. 现在,您尝试从country_id = 1删除记录错误的记录。
  4. 这种情况正在发生,因为外键仍然存在且处于活动状态。它不能让您删除父记录,因为子表中可能有记录,它们仍然引用父表中的记录。要删除父表中的记录,需要禁用约束。

    编辑: 我编辑引用正确的外键列。即使foregin键位于tree_instance列,您也可以删除子表中的记录,但是您将无法从父表中删除记录,因为子表中的外键引用了{{ 1}}父表的列。父表上不允许删除,因为子表中可能有一些记录,它从父表引用值time_segment

答案 1 :(得分:0)

在失败的DELETE FROM tree_instance WHERE country_id = 1语句之前 - 检查node_instance是否包含country_id = 1的行。如果是,则可能尚未提交先前的修改。因此,检查是否存在已存在的交易;当然,如果你使用它们。

答案 2 :(得分:0)

此问题的解决方案是MySQL非唯一约束是特定于MySQL的,如docs中所述:

  

引用非UNIQUE键的FOREIGN KEY约束不是标准SQL,而是InnoDB扩展。

对非唯一索引的约束可防止删除任何匹配的行。任何。无论是否还有其他记录仍然存在约束。总的答案是,在非唯一字段上使用约束是一个坏主意,简单。