Как обновить FK, связанный с несколькими таблицами - Каскад при обновлении - PullRequest
0 голосов
/ 12 января 2019

У меня есть 3 таблицы, которые связаны друг с другом

  1. Задача
  2. клиент
  3. соблюдение

Соотношение, как показано на схеме ниже relationship

Таблица compliance имеет внешний ключ, как показано ниже compliance table

Таблица task имеет внешний ключ, как показано ниже task table

Issue: Когда я редактирую / обновляю 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. Если это правда, то каково решение обновить 3 таблицы новыми clientno?

РЕДАКТИРОВАТЬ 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

Ответы [ 2 ]

0 голосов
/ 24 января 2019

Я думаю, что ваша проблема связана с использованием изменяемых полей в качестве первичных ключей

Вы можете уменьшить это, используя суррогатный неизменяемый первичный ключ и добавив уникальный ключ в изменяемые поля. Вы должны иметь возможность применять те же ограничения, что и раньше, без ущерба для целостности данных

Например:

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. Это может быть ссылка на клиентскую таблицу

0 голосов
/ 12 января 2019

Проблема связана со способом объявления отношений.

Прежде всего, как прокомментировал @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, с которым обработка отношений довольно проста.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...