我有3个表相互链接
问题:当我在clientno
表中编辑/更新client
时,我明白了
1452: Cannot add or update a child row: a foreign key constraint fails
(`task`, CONSTRAINT `task_ibfk_1` FOREIGN KEY (`officeid`, `clientid`) REFERENCES `client` (`officeid`, `clientno`) ON UPDATE CASCADE)
我预计当clientno
在client
表中更改时,同样会在complaince
和task
表中更新。
我想我正在达到InnoDB引擎的已知限制。哪个不允许级联更新到FK。如果这是真的,那么用新的clientno
更新3个表的解决方案是什么?
编辑1:正如@pankaj所指出的,如何克服
如果ON UPDATE CASCADE递归以更新它在级联期间先前已更新的相同表,则其行为类似于RESTRICT。这意味着您不能使用自引用ON UPDATE CASCADE操作。这是为了防止级联更新导致的无限循环。
编辑2:
create table client
(
officeid char(6) not null,
clientno char(10) not null,
fname varchar(40) not null,
primary key (officeid, clientno)
);
create index officeid_clientno
on client (officeid, clientno);
create table compliance
(
officeid char(6) not null,
id smallint(5) unsigned not null,
clientid char(10) not null,
primary key (officeid, id),
constraint compliance_ibfk_2
foreign key (officeid, clientid) references client (officeid, clientno)
on update cascade
on delete cascade
);
create index officeid_clientid
on compliance (officeid, clientid, id);
create table task
(
officeid char(6) not null,
taskno char(10) not null,
clientid char(10) not null,
taskname varchar(50) not null,
complianceid smallint(5) unsigned null,
primary key (officeid, taskno),
constraint task_ibfk_1
foreign key (officeid, clientid) references client (officeid, clientno)
on update cascade,
constraint task_ibfk_4
foreign key (officeid, clientid, complianceid) references compliance (officeid, clientid, id)
on update cascade
);
create index officeid_clientid_complianceid
on task (officeid, clientid, complianceid);
仅供参考:我尝试过mariadb 10.3以及mysql 8.0
问题与声明关系的方式有关。
首先,正如@Nick评论的那样,task
和client
之间不需要关系,因为这已经与compliance
的关系所涵盖。正如你在this db fiddle中看到的那样,评论这个多余约束的声明足以使错误消失。
create table task
(
officeid char(6) not null,
...
primary key (officeid, taskno),
-- constraint task_ibfk_1
-- foreign key (officeid, clientid) references client (officeid, clientno)
-- on update cascade,
constraint task_ibfk_4
foreign key (officeid, clientid, complianceid) references compliance (officeid, clientid, id)
on update cascade
);
另一个建议是在所有表中使用自动增量主键(您可以使用UNIQUE
索引来强制执行复合参照完整性规则)。这是继续使用MySQL的最常用方法,处理关系非常简单。
我认为你的问题源于使用可变字段作为主键
您可以通过使用代理不可变主键并向可变字段添加唯一键来缓解此问题。您应该能够应用与以前相同的约束,而不会影响数据完整性
例如:
CREATE TABLE client (
id INT(10) UNSIGNED NOT NULL AUTO-INCREMENT PRIMARY,
officeid CHAR(6) NOT NULL,
clientno CHAR(10) NOT NULL,
fname VARCHAR(40) NOT NULL
);
CREATE UNIQUE INDEX uq-client-officeid-clientno IN client (officeid, clientno);
CREATE TABLE compliance (
id SMALLINT(5) UNSIGNED NOT NULL AUTO-INCREMENT PRIMARY,
client_id INT(10) UNSIGNED NOT NULL,
CONSTRAINT fk-compliance-client-id FOREIGN KEY id
REFERENCES client (id)
);
CREATE INDEX ix-compliance-id-client_id IN compliance (id, client_id);
CREATE TABLE task (
id INT(10) UNSIGNED NOT NULL AUTO-INCREMENT PRIMARY,
client_id INT(10) UNSIGNED NOT NULL,
compliance_id SMALLINT(5) UNSIGNED NULL,
taskno CHAR(10) NOT NULL,
taskname VARCHAR(50) NOT NULL,
CONSTRAINT fk-task-client-id FOREIGN KEY id
REFERENCES client (id),
CONSTRAINT fk-task-compliance-id-client_id FOREIGN KEY (compliance_id, client_id)
REFERENCES compliance (id, client_id)
);
此表结构模仿您当前的约束,并允许您更新clientno
而无需级联
注意外键fk-task-compliance-id-client_id
,它确保任务引用的合规性包含正确的client_id
我还会考虑一个单独的表,office,带有代理整数主键,并包含基于字符的officeid
。然后,这可以由客户端表引用