假设我有两个表,a
和 b
。表a
包含对b
的可选FOREIGN KEY
引用。表b
没有对表a
的FOREIGN KEY
引用,也不应该有。原因是表 a
不是唯一可能引用表 b
中的行的表:表 x
和 y
也可能引用 b
,并且将来可能会添加更多表,这些表可能会引用 b
中的行。
因此,表 b
中的每一行都恰好有一个“所有者行”,该行可能属于 a
、x
、y
,或者可能是许多其他表中的任何一个。
现在,如果删除表 b
中的一行,我希望它从 a
、x
设置对其自身的外键引用,或y
,如果有的话,为空。我知道我可以在 a
和其他表的外键约束中使用 ON DELETE SET NULL
来完成此操作,这样就可以解决这个问题。
但是,如果“所有者行”被删除,无论该行是否位于 a
、x
、y
或其他位置,我希望将 b
中的相应行也删除。这是我不知道该怎么做的事情。
简而言之:
a
引用b
。这是一个可选引用,并非所有a
都会有b
。- (
x
、y
等表也与b
有类似的关系)
- (
b
不会也不应该引用a
或任何其他表。- 如果我从
a
中删除,并且给定的a
有相应的b
,则b
应该是已删除。 - 如果我从
b
中删除,并且任何其他表包含对该b
的引用,则该引用应设置为 null。
我该如何实现这个目标?
最佳答案
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。”
我们也许可以使用触发器来完成此任务,但是我们遇到了一些问题,即触发器中的语句可以引用哪些表。这可能会更好地使用应用程序逻辑来处理,而不是数据库规则或触发器。
如果我要尝试触发,那么类似
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
的删除将触发“删除后”触发器;并且将对 b
执行 DELETE,外键将查找行 id=3
引用,并尝试将 b_id
列设置为NULL...但是该行可能已经被初始 DELETE 语句锁定...我只是不确定在这种情况下会发生什么;我们遇到了触发器的一些限制和限制(例如禁止修改触发触发器的语句中引用的表中的行)
关于mysql - 双向使用 ON DELETE,具有 1-1 关系,其中只有表有外键,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55801689/