假设我有两张桌子,a
和b
。表a
包含FOREIGN KEY
的可选b
参考。表b
没有FOREIGN KEY
参考表a
,不应该。这样做的原因是表a
不是唯一可以从表b
引用行的表:tables x
和y
也可能引用b
,将来可能会添加更多可能引用b
行的表。
因此,表b
中的每一行都只有一个“所有者行”,可能属于a
,x
,y
,或者可能属于其他许多表中的任何一个。
现在,如果删除表b
中的一行,我希望它将a
,x
或y
中的外键引用设置为null,如果有的话,则为null。我知道我可以使用ON DELETE SET NULL
在a
和其他表的外键约束中完成此操作,因此需要注意。
但是,如果删除“所有者行”,无论该行是否存在于a
,x
,y
等等,我都希望删除b
中的相应行。这是我不知道该怎么办。
简而言之:
a
引用b
。这是一个可选参考,并非所有a
s都有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。”
我们或许可以通过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
的删除将触发“删除后”触发器;并且将在b
上执行DELETE,外键将找到行id=3
引用,并尝试将b_id
列设置为NULL ...但该行可能已被初始DELETE语句锁定...我只是不确定在这种情况下会发生什么;并且我们对触发器遇到了一些限制和限制(比如修改触发触发器的语句中引用的表中的行)