我如何使用 MySQL 的递归关系进行 CASCADE ON DELETE
How can I CASCADE ON DELETE with a Recursive Relationships with MySQL
我有这个代码:
CREATE TABLE Employee (idEmployee int PRIMARY KEY, nane varchar(100));
CREATE TABLE Friend (idFriendA integer, idFriendB integer,
FOREIGN KEY (idFriendA) REFERENCES Employee (idEmployee) ON DELETE CASCADE,
FOREIGN KEY (idFriendB) REFERENCES Employee (idEmployee) ON DELETE CASCADE);
INSERT INTO Employee (idEmployee, nane) VALUES (0, 'Bob'),(1, 'Jean');
INSERT INTO Friend (idFriendA, idFriendB) VALUES (0, 1);
而且我希望如果我删除 Employee 中的 id 0,它会使用关系 Friend 级联删除 Employee 中的 id 1。
我试过为 idFriendB 添加主键,但没有成功
另一种解决方案是触发器,但如果我们尝试更改触发器中的 table 以在同一个 table 上删除,我们会收到 table 正在变异的所有错误。
另一种方法是删除 Friends 中的条目并使用触发器删除 Employees 中的 2 行。
注意我不确定逻辑是什么。如果其中一名员工有另一个朋友会怎样?我们是否级联更多删除?看看 Bill 的例子,当她失去朋友 Bob 时,Bill 突然失去了他的朋友 Jean。我们在哪里停下来?员工可以没有朋友吗?
CREATE TABLE Employee (
idEmployee int PRIMARY KEY,
nane varchar(100));
CREATE TABLE Friend (
idFriendA integer,
idFriendB integer,
FOREIGN KEY (idFriendA)
REFERENCES Employee (idEmployee)
ON DELETE CASCADE,
FOREIGN KEY (idFriendB)
REFERENCES Employee (idEmployee)
ON DELETE CASCADE);
INSERT INTO Employee
(idEmployee, nane) VALUES
(0, 'Bob'),
(1, 'Jean'),
(2,'Bill');
INSERT INTO Friend
(idFriendA, idFriendB) VALUES
(0, 1),
(1, 2);
✓
✓
✓
✓
create trigger deleteFriend
before delete on Friend
for each row
delete from Employee
where idEmployee = old.idFriendA
or idEmployee = old.idFriendB;
✓
select * from Friend;
select * from Employee;
idFriendA | idFriendB
--------: | --------:
0 | 1
1 | 2
idEmployee | nane
---------: | :---
0 | Bob
1 | Jean
2 | Bill
delete from Friend where idFriendA = 0
✓
select * from Friend;
select * from Employee;
idFriendA | idFriendB
--------: | --------:
idEmployee | nane
---------: | :---
2 | Bill
db<>fiddle here
根据说明我建议最好只用一个table。我们使用递归外键来确保父项存在。 (我们为文件系统 Id 1 的根例外,它是 /
)
CREATE TABLE Files (
fileId integer PRIMARY KEY,
name varchar(100) NOT NULL,
parentId integer,
FOREIGN KEY (parentId)
REFERENCES Files (fileId)
ON DELETE CASCADE,
CONSTRAINT Parent_Not_Self CHECK
(parentId <> fileId OR fileId = 1));
✓
INSERT INTO Files VALUES
(1,'/',1);
✓
INSERT INTO Files VALUES
(2,'/ twin',2);
Check constraint 'Parent_Not_Self' is violated.
INSERT INTO Files VALUES
(3,'alone',4);
Cannot add or update a child row: a foreign key constraint fails (`db_1032216260`.`Files`, CONSTRAINT `Files_ibfk_1` FOREIGN KEY (`parentId`) REFERENCES `Files` (`fileId`) ON DELETE CASCADE)
INSERT INTO Files VALUES
(2,'/etc',1),
(3,'/home',1),
(4,'/mnt',1),
(5,'/home/user_name',3);
✓
SELECT * FROM Files p
JOIN Files c
ON c.parentId = p.fileId;
fileId | name | parentId | fileId | name | parentId
-----: | :---- | -------: | -----: | :-------------- | -------:
1 | / | 1 | 1 | / | 1
1 | / | 1 | 2 | /etc | 1
1 | / | 1 | 3 | /home | 1
1 | / | 1 | 4 | /mnt | 1
3 | /home | 1 | 5 | /home/user_name | 3
db<>fiddle here
我有这个代码:
CREATE TABLE Employee (idEmployee int PRIMARY KEY, nane varchar(100));
CREATE TABLE Friend (idFriendA integer, idFriendB integer,
FOREIGN KEY (idFriendA) REFERENCES Employee (idEmployee) ON DELETE CASCADE,
FOREIGN KEY (idFriendB) REFERENCES Employee (idEmployee) ON DELETE CASCADE);
INSERT INTO Employee (idEmployee, nane) VALUES (0, 'Bob'),(1, 'Jean');
INSERT INTO Friend (idFriendA, idFriendB) VALUES (0, 1);
而且我希望如果我删除 Employee 中的 id 0,它会使用关系 Friend 级联删除 Employee 中的 id 1。
我试过为 idFriendB 添加主键,但没有成功
另一种解决方案是触发器,但如果我们尝试更改触发器中的 table 以在同一个 table 上删除,我们会收到 table 正在变异的所有错误。
另一种方法是删除 Friends 中的条目并使用触发器删除 Employees 中的 2 行。
注意我不确定逻辑是什么。如果其中一名员工有另一个朋友会怎样?我们是否级联更多删除?看看 Bill 的例子,当她失去朋友 Bob 时,Bill 突然失去了他的朋友 Jean。我们在哪里停下来?员工可以没有朋友吗?
CREATE TABLE Employee ( idEmployee int PRIMARY KEY, nane varchar(100)); CREATE TABLE Friend ( idFriendA integer, idFriendB integer, FOREIGN KEY (idFriendA) REFERENCES Employee (idEmployee) ON DELETE CASCADE, FOREIGN KEY (idFriendB) REFERENCES Employee (idEmployee) ON DELETE CASCADE); INSERT INTO Employee (idEmployee, nane) VALUES (0, 'Bob'), (1, 'Jean'), (2,'Bill'); INSERT INTO Friend (idFriendA, idFriendB) VALUES (0, 1), (1, 2);
✓ ✓ ✓ ✓
create trigger deleteFriend before delete on Friend for each row delete from Employee where idEmployee = old.idFriendA or idEmployee = old.idFriendB;
✓
select * from Friend; select * from Employee;
idFriendA | idFriendB --------: | --------: 0 | 1 1 | 2 idEmployee | nane ---------: | :--- 0 | Bob 1 | Jean 2 | Bill
delete from Friend where idFriendA = 0
✓
select * from Friend; select * from Employee;
idFriendA | idFriendB --------: | --------: idEmployee | nane ---------: | :--- 2 | Bill
db<>fiddle here
根据说明我建议最好只用一个table。我们使用递归外键来确保父项存在。 (我们为文件系统 Id 1 的根例外,它是 /
)
CREATE TABLE Files ( fileId integer PRIMARY KEY, name varchar(100) NOT NULL, parentId integer, FOREIGN KEY (parentId) REFERENCES Files (fileId) ON DELETE CASCADE, CONSTRAINT Parent_Not_Self CHECK (parentId <> fileId OR fileId = 1));
✓
INSERT INTO Files VALUES (1,'/',1);
✓
INSERT INTO Files VALUES (2,'/ twin',2);
Check constraint 'Parent_Not_Self' is violated.
INSERT INTO Files VALUES (3,'alone',4);
Cannot add or update a child row: a foreign key constraint fails (`db_1032216260`.`Files`, CONSTRAINT `Files_ibfk_1` FOREIGN KEY (`parentId`) REFERENCES `Files` (`fileId`) ON DELETE CASCADE)
INSERT INTO Files VALUES (2,'/etc',1), (3,'/home',1), (4,'/mnt',1), (5,'/home/user_name',3);
✓
SELECT * FROM Files p JOIN Files c ON c.parentId = p.fileId;
fileId | name | parentId | fileId | name | parentId -----: | :---- | -------: | -----: | :-------------- | -------: 1 | / | 1 | 1 | / | 1 1 | / | 1 | 2 | /etc | 1 1 | / | 1 | 3 | /home | 1 1 | / | 1 | 4 | /mnt | 1 3 | /home | 1 | 5 | /home/user_name | 3
db<>fiddle here