如何更新链接到多个表的 FK - 更新时的级联
Posted
技术标签:
【中文标题】如何更新链接到多个表的 FK - 更新时的级联【英文标题】:How to update FK linked to multiple table - Cascade on Update 【发布时间】:2019-01-12 00:53:27 【问题描述】:我有 3 个相互链接的表
-
任务
客户
合规
关系如下图所示
compliance
表的外键如下
task
表的外键如下
问题:
当我在client
表中编辑/更新clientno
时,我得到了
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)
我预计,当 client
表中的 clientno
发生更改时,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 中尝试过
【问题讨论】:
这可能会有所帮助 - ***.com/a/5446693/4050261 @GMB,添加表创建语句 从task
到compliance
创建一个包含officeid
和clientid
的外键没有意义,因为您已经将这些列包含在client
的外键中(这是适当的表)(并且compliance
已经具有相同的外键关系)。您应该将该外键更改为仅位于 complianceid
问题在this db fiddlethis db fiddleMariaDB 10.3 上重现
@Nick,这将导致Task
表中的记录与Compliance
表中的记录不一样clientid
【参考方案1】:
问题与声明关系的方式有关。
首先,正如@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 的最常用方法,处理关系非常简单。
【讨论】:
并非所有任务都通过Compliance
表链接到Client
表。因此complianceid
在Task
表中可以为空。感谢您创建小提琴。我已经添加了我的 sql 语句。 dbfiddle.uk/…
我同意@AdarshMadrecha,需要 2 个 FK。第一个到Client
表和另一个到Complaince
表使用clientid & complianceid
【参考方案2】:
我认为您的问题源于使用可变字段作为主键
您可以通过使用代理不可变主键并向可变字段添加唯一键来缓解这种情况。您应该能够在不影响数据完整性的情况下应用与以前相同的约束
例如:
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
。这可以被客户端表引用
【讨论】:
以上是关于如何更新链接到多个表的 FK - 更新时的级联的主要内容,如果未能解决你的问题,请参考以下文章