我有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中都尝试过
答案 0 :(得分:3)
问题与声明关系的方式有关。
首先,如@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进行处理的最常用的方法,通过这种方法可以很轻松地处理关系。
答案 1 :(得分:0)
我认为您的问题源于使用可变字段作为主键
您可以通过使用代理不可变主键并将唯一键添加到可变字段来减轻这种情况。您应该能够像以前一样应用相同的约束,而不会影响数据完整性
例如:
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
。然后可以由客户表引用