Использование ON DELETE в обоих направлениях с отношением 1-1, где только таблица имеет внешний ключ - PullRequest
0 голосов
/ 23 апреля 2019

Предположим, у меня есть две таблицы, a и b. Таблица a содержит необязательную ссылку FOREIGN KEY на b. Таблица b не имеет FOREIGN KEY ссылку на таблицу a и не должна. Причина этого в том, что таблица a - не единственная таблица, которая может ссылаться на строку из таблицы b: таблицы x и y могут также ссылаться на b, и в будущем может быть добавлено больше таблиц. который может ссылаться на строку из b.

Итак, каждая строка в таблице b имеет ровно одну «строку владельца», которая может принадлежать a, x, y или, возможно, любой из ряда других таблиц.

Теперь, если строка из таблицы b удалена, я хочу, чтобы она установила для себя ссылку на внешний ключ от a, x или y, если она есть, на ноль. Я знаю, что могу сделать это, используя ON DELETE SET NULL в ограничениях внешнего ключа для a и других таблиц, так что об этом позаботятся.

Однако, если «строка владельца» будет удалена, независимо от того, находится ли эта строка в a, x, y или что-то еще, я хочу, чтобы также была удалена соответствующая строка из b , Это то, что я не знаю, как это сделать.

Короче говоря:

  1. a ссылки b. Это дополнительная ссылка, не все a s будут иметь b.
    • (x, y и другие таблицы также имеют сходные отношения с b)
  2. b не ссылается и не должно ссылаться на a или любую из этих других таблиц.
  3. Если я удаляю из a и если у данного a есть соответствующий b, то b следует удалить.
  4. Если я удаляю из b, а любая другая таблица содержит ссылку на этот b, ссылка должна быть равна нулю.

Как бы мне этого добиться?

1 Ответ

1 голос
/ 23 апреля 2019
create table a
( ...
, b_id  bigint default null comment 'fk ref b.id'
, constraint a_b_id foreign key (b_id) reference b (id) on delete set null 
, ...
) engine=innodb

таблицы x и y определены аналогично, с пустыми столбцами внешнего ключа

create table x 
( ...
, b_id  bigint default null comment 'fk ref b.id'
, constraint x_b_id foreign key (b_id) references b (id) on delete set null 
, ...
) engine=innodb

и

create table y 
( ...
, b_id  bigint default null comment 'fk ref b.id'
, constraint y_b_id foreign key (b_id) references b (id) on delete set null 
, ...
) engine=innodb

Когда строка удаляется из b, то любые значения столбца b_id в любой из трех таблиц ссылаются на удаленную строку, эти значения будут изменены на NULL.


В MySQL нет декларативного ограничения, которое будет выполнять 3.

«Если я удаляю из a и если данному a соответствует b, этот b следует удалить.»

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

Если я собирался сделать попытку триггера, то что-то вроде

 DELIMITER $$

 CREATE TRIGGER a_ad
 AFTER DELETE ON a
 FOR EACH ROW
 BEGIN
    DELETE FROM b WHERE b.id = OLD.b_id ;
 END$$

 DELIMITER ;

(Я не уверен, что это будет разрешено, или если будет выдано сообщение об ошибке ... рассмотрим

table b
---------
row id=42

и

table a
-------
row id=2  b_id=42
row id=3  b_id=42

рассмотрим этот оператор SQL

DELETE FROM a WHERE a.id IN (2,3);

Удаление строки id=2 запускает триггер "после удаления"; и он выполнит DELETE для b, внешний ключ найдет строку id=3, на которую ссылается, и попытается установить для столбца b_id значение NULL ... но эта строка может быть уже заблокирована исходным оператором DELETE. .. Я просто не уверен, что произойдет в этом сценарии; и мы сталкиваемся с некоторыми ограничениями на триггеры (например, на изменение строк в таблицах, на которые ссылается оператор, запускающий триггер)

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