如何更新链接到多个表的FK - 更新级联

问题描述 投票:0回答:2

我有3个表相互链接

  1. 任务
  2. 客户
  3. 合规

这种关系如下图relationship 所示

compliance表的外键如下compliance table

task表的外键如下task table

问题:当我在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)

我预计当clientnoclient表中更改时,同样会在complaincetask表中更新。

我想我正在达到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

mysql sql mariadb cascade referential-integrity
2个回答
3
投票

问题与声明关系的方式有关。

首先,正如@Nick评论的那样,taskclient之间不需要关系,因为这已经与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的最常用方法,处理关系非常简单。


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。然后,这可以由客户端表引用

© www.soinside.com 2019 - 2024. All rights reserved.