无法删除或更新父行:更新父级时外键约束失败

dij*_*tra 1 mysql sql

我有一张这样的桌子:

CREATE TABLE `testt` (
  `id` int(11) NOT NULL,
  `pid` int(11) DEFAULT NULL,
  `active` int(11) NOT NULL DEFAULT '0',
  `pacitve` int(11) NOT NULL DEFAULT '0',
  PRIMARY KEY (`id`),
  KEY `id` (`id`,`active`),
  KEY `pid` (`pid`,`pacitve`),
  CONSTRAINT `active_fk` FOREIGN KEY (`pid`, `pacitve`) REFERENCES `testt` (`id`, `active`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=latin1
Run Code Online (Sandbox Code Playgroud)

pid代表父ID

我的数据是这样的:

id     pid    active  pactive

1      NULL    0       0

2      1       0       0

3      1       0       0

4      2       0       0
Run Code Online (Sandbox Code Playgroud)

当我为id = 1设置active = 1时,我得到了这个异常.为什么我收到此错误?删除工作正常.我的目的是当我为id = 1设置active = 1时,应该更新id = 1的所有子节点.

Gar*_*thD 8

问题是你已经强制(pid,pacitve)匹配同一个表中的另一个记录,所以对于id 1,你有pid = 1和pacitve = 0,这很好,因为父行有活动= 0.当你改变父行中不再有相应的行破坏表的完整性.

即使你有CASCADE选项,这些也不适用于引用同一个表的外键(它允许你创建它,但实际上并没有对更新或删除做任何事情).该文档状态:

如果ON UPDATE CASCADE或ON UPDATE SET NULL递归更新它在级联期间先前更新的同一个表,它就像RESTRICT一样.这意味着您不能使用自引用ON UPDATE CASCADE或ON UPDATE SET NULL操作.这是为了防止级联更新导致的无限循环.另一方面,自引用ON DELETE SET NULL是可能的,就像自引用ON DELETE CASCADE一样.级联操作可能不会嵌套超过15级.

还要注意,创建一个引用非唯一索引的外键不是标准的,对我来说似乎是一个相当奇怪的偏离标准.然而,文件再次说明:

InnoDB允许外键约束引用非唯一键.这是标准SQL的InnoDB扩展.

您的整个架构设置错误,您根本不需要激活外键引用,也不需要将子状态存储在子节点中,这可以在select中实现.你的表结构应该是:

CREATE TABLE `testt` (
    `id` int(11) NOT NULL,
    `pid` int(11) DEFAULT NULL,
    `active` int(11) NOT NULL DEFAULT '0'
    PRIMARY KEY (`id`),
    KEY `id` (`id`,`active`),
    KEY `pid` (`pid`,`pacitve`),
    CONSTRAINT `pid_fk` FOREIGN KEY (`pid`) REFERENCES `testt` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
Run Code Online (Sandbox Code Playgroud)

然后,如果您需要知道父级的状态,您可以使用:

SELECT  c.id, c.pid, c.active, p.active AS pactive
FROM    testt c
        LEFT JOIN testt p
            ON c.pid = p.id;
Run Code Online (Sandbox Code Playgroud)

更新前的示例

更新后的示例