Tables with mixed ON DELETE CASCADE and ON DELETE RESTRICT, rule set with recursion? The 2019...
Patience, young "Padovan"
How to change the limits of integration
Why isn't airport relocation done gradually?
Is bread bad for ducks?
What is the steepest angle that a canal can be traversable without locks?
Could JWST stay at L2 "forever"?
What tool would a Roman-age civilization have to grind silver and other metals into dust?
Why can Shazam do this?
Why is it "Tumoren" and not "Tumore"?
Why is my p-value correlated to difference between means in two sample tests?
How to create dashed lines/arrows in Illustrator
Springs with some finite mass
Inversion Puzzle
Is domain driven design an anti-SQL pattern?
Why Did Howard Stark Use All The Vibranium They Had On A Prototype Shield?
I looked up a future colleague on LinkedIn before I started a job. I told my colleague about it and he seemed surprised. Should I apologize?
Inflated grade on resume at previous job, might former employer tell new employer?
Is three citations per paragraph excessive for undergraduate research paper?
How can I create a character who can assume the widest possible range of creature sizes?
Dual Citizen. Exited the US on Italian passport recently
How to deal with fear of taking dependencies
Does a dangling wire really electrocute me if I'm standing in water?
Pristine Bit Checking
How can I fix this gap between bookcases I made?
Tables with mixed ON DELETE CASCADE and ON DELETE RESTRICT, rule set with recursion?
The 2019 Stack Overflow Developer Survey Results Are InReferential Integrity in schema, cascading the renamingCan I use `on delete set null` on a compound foreign key which contains a primary key column?Why can't we have multiple cascade paths?Several Foreign Key and Cascade Delete SQL ServerChanging Action on Delete to CascadeVisualize the effects of a cascading delete or update?Is there a possibility to see cascade path in MS SQLCycles or multiple cascade paths with on delete set null: really?Delete all records in tables with reference to another referenceHow to find out if entity is used in relations somewhere in database?
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty{ margin-bottom:0;
}
Not sure if this is a generic question, but unless not, this is MySQL 5.6.
We have a database consisting of ~300 tables, INNODB, all connected with proper foreign keys. One of these tables can be seen as the parent. My desired end result is that I can execute one delete on this table, and have all related information in all other 300 tables deleted as well.
However, the declared foreign keys are a mix of RESTRICT and CASCADE for ON DELETE and I'm trying to understand the rule set when these are applied in recursion.
I've been trying to find information on this, but no luck. Testing appears to indicate that RESTRICT blocks a CASCADE, but not necessarily. Consider this example:
Tables: A, B, C
B -> A (ON DELETE CASCADE)
C -> A (ON DELETE CASCADE)
C -> B (ON DELETE RESTRICT)
In this example, rows from B and C are deleted when A is deleted. However, since C -> B has a RESTRICT one could think that matching rows would block a CASCADE. But this is not the case. However, if I add an additional table D like this:
Tables: A, B, C, D
B -> A (ON DELETE CASCADE)
C -> A (ON DELETE CASCADE)
C -> B (ON DELETE RESTRICT)
D -> C (ON DELETE RESTRICT)
A delete from A is blocked by the RESTRICT from D to C.
A simple approach would be to simply use CASCADE everywhere, but I'm curious about the rule set. Or if the behaviour is either implementation dependent or simply undefined.
Is it based on level of depth of the CASCADING? That is, the shortest path determines the effective ON DELETE rule to use? What if multiple paths have the same length, with different rules?
mysql delete recursive cascade
bumped to the homepage by Community♦ 10 mins ago
This question has answers that may be good or bad; the system has marked it active so that they can be reviewed.
|
show 6 more comments
Not sure if this is a generic question, but unless not, this is MySQL 5.6.
We have a database consisting of ~300 tables, INNODB, all connected with proper foreign keys. One of these tables can be seen as the parent. My desired end result is that I can execute one delete on this table, and have all related information in all other 300 tables deleted as well.
However, the declared foreign keys are a mix of RESTRICT and CASCADE for ON DELETE and I'm trying to understand the rule set when these are applied in recursion.
I've been trying to find information on this, but no luck. Testing appears to indicate that RESTRICT blocks a CASCADE, but not necessarily. Consider this example:
Tables: A, B, C
B -> A (ON DELETE CASCADE)
C -> A (ON DELETE CASCADE)
C -> B (ON DELETE RESTRICT)
In this example, rows from B and C are deleted when A is deleted. However, since C -> B has a RESTRICT one could think that matching rows would block a CASCADE. But this is not the case. However, if I add an additional table D like this:
Tables: A, B, C, D
B -> A (ON DELETE CASCADE)
C -> A (ON DELETE CASCADE)
C -> B (ON DELETE RESTRICT)
D -> C (ON DELETE RESTRICT)
A delete from A is blocked by the RESTRICT from D to C.
A simple approach would be to simply use CASCADE everywhere, but I'm curious about the rule set. Or if the behaviour is either implementation dependent or simply undefined.
Is it based on level of depth of the CASCADING? That is, the shortest path determines the effective ON DELETE rule to use? What if multiple paths have the same length, with different rules?
mysql delete recursive cascade
bumped to the homepage by Community♦ 10 mins ago
This question has answers that may be good or bad; the system has marked it active so that they can be reviewed.
Are you sure the case with 3 tables (A, B, C) succeeds always?
– ypercubeᵀᴹ
Mar 2 '18 at 14:08
dbfiddle.uk 3 cases, some fail, some succeed
– ypercubeᵀᴹ
Mar 2 '18 at 14:24
By 3 cases, are you talking about the 3 possible cases you can have with rows in this example? My assumption here was was 3 tables will all non-nullable fields, with rows that make use of the foreign keys.
– Matthias
Mar 2 '18 at 14:42
I'm trying to understand the general rule set though, without regard to the rows. On a logical level. Ultimately, I want to implement an algorithm that by just analysing the tables' structure can verify whether a delete will always be a success, or not (only succeeding under some conditions is a fail).
– Matthias
Mar 2 '18 at 14:44
Yes, with 3 cases I meant the specific inserts. Deletingaid=1
andaid=2
fail. Deletingaid=3
succeeds. The desgin is exactly as your question, 3 tables, not nullable columns, and FKs from (B->A, C->B, C->A).
– ypercubeᵀᴹ
Mar 2 '18 at 14:52
|
show 6 more comments
Not sure if this is a generic question, but unless not, this is MySQL 5.6.
We have a database consisting of ~300 tables, INNODB, all connected with proper foreign keys. One of these tables can be seen as the parent. My desired end result is that I can execute one delete on this table, and have all related information in all other 300 tables deleted as well.
However, the declared foreign keys are a mix of RESTRICT and CASCADE for ON DELETE and I'm trying to understand the rule set when these are applied in recursion.
I've been trying to find information on this, but no luck. Testing appears to indicate that RESTRICT blocks a CASCADE, but not necessarily. Consider this example:
Tables: A, B, C
B -> A (ON DELETE CASCADE)
C -> A (ON DELETE CASCADE)
C -> B (ON DELETE RESTRICT)
In this example, rows from B and C are deleted when A is deleted. However, since C -> B has a RESTRICT one could think that matching rows would block a CASCADE. But this is not the case. However, if I add an additional table D like this:
Tables: A, B, C, D
B -> A (ON DELETE CASCADE)
C -> A (ON DELETE CASCADE)
C -> B (ON DELETE RESTRICT)
D -> C (ON DELETE RESTRICT)
A delete from A is blocked by the RESTRICT from D to C.
A simple approach would be to simply use CASCADE everywhere, but I'm curious about the rule set. Or if the behaviour is either implementation dependent or simply undefined.
Is it based on level of depth of the CASCADING? That is, the shortest path determines the effective ON DELETE rule to use? What if multiple paths have the same length, with different rules?
mysql delete recursive cascade
Not sure if this is a generic question, but unless not, this is MySQL 5.6.
We have a database consisting of ~300 tables, INNODB, all connected with proper foreign keys. One of these tables can be seen as the parent. My desired end result is that I can execute one delete on this table, and have all related information in all other 300 tables deleted as well.
However, the declared foreign keys are a mix of RESTRICT and CASCADE for ON DELETE and I'm trying to understand the rule set when these are applied in recursion.
I've been trying to find information on this, but no luck. Testing appears to indicate that RESTRICT blocks a CASCADE, but not necessarily. Consider this example:
Tables: A, B, C
B -> A (ON DELETE CASCADE)
C -> A (ON DELETE CASCADE)
C -> B (ON DELETE RESTRICT)
In this example, rows from B and C are deleted when A is deleted. However, since C -> B has a RESTRICT one could think that matching rows would block a CASCADE. But this is not the case. However, if I add an additional table D like this:
Tables: A, B, C, D
B -> A (ON DELETE CASCADE)
C -> A (ON DELETE CASCADE)
C -> B (ON DELETE RESTRICT)
D -> C (ON DELETE RESTRICT)
A delete from A is blocked by the RESTRICT from D to C.
A simple approach would be to simply use CASCADE everywhere, but I'm curious about the rule set. Or if the behaviour is either implementation dependent or simply undefined.
Is it based on level of depth of the CASCADING? That is, the shortest path determines the effective ON DELETE rule to use? What if multiple paths have the same length, with different rules?
mysql delete recursive cascade
mysql delete recursive cascade
asked Mar 1 '18 at 21:37
MatthiasMatthias
61
61
bumped to the homepage by Community♦ 10 mins ago
This question has answers that may be good or bad; the system has marked it active so that they can be reviewed.
bumped to the homepage by Community♦ 10 mins ago
This question has answers that may be good or bad; the system has marked it active so that they can be reviewed.
Are you sure the case with 3 tables (A, B, C) succeeds always?
– ypercubeᵀᴹ
Mar 2 '18 at 14:08
dbfiddle.uk 3 cases, some fail, some succeed
– ypercubeᵀᴹ
Mar 2 '18 at 14:24
By 3 cases, are you talking about the 3 possible cases you can have with rows in this example? My assumption here was was 3 tables will all non-nullable fields, with rows that make use of the foreign keys.
– Matthias
Mar 2 '18 at 14:42
I'm trying to understand the general rule set though, without regard to the rows. On a logical level. Ultimately, I want to implement an algorithm that by just analysing the tables' structure can verify whether a delete will always be a success, or not (only succeeding under some conditions is a fail).
– Matthias
Mar 2 '18 at 14:44
Yes, with 3 cases I meant the specific inserts. Deletingaid=1
andaid=2
fail. Deletingaid=3
succeeds. The desgin is exactly as your question, 3 tables, not nullable columns, and FKs from (B->A, C->B, C->A).
– ypercubeᵀᴹ
Mar 2 '18 at 14:52
|
show 6 more comments
Are you sure the case with 3 tables (A, B, C) succeeds always?
– ypercubeᵀᴹ
Mar 2 '18 at 14:08
dbfiddle.uk 3 cases, some fail, some succeed
– ypercubeᵀᴹ
Mar 2 '18 at 14:24
By 3 cases, are you talking about the 3 possible cases you can have with rows in this example? My assumption here was was 3 tables will all non-nullable fields, with rows that make use of the foreign keys.
– Matthias
Mar 2 '18 at 14:42
I'm trying to understand the general rule set though, without regard to the rows. On a logical level. Ultimately, I want to implement an algorithm that by just analysing the tables' structure can verify whether a delete will always be a success, or not (only succeeding under some conditions is a fail).
– Matthias
Mar 2 '18 at 14:44
Yes, with 3 cases I meant the specific inserts. Deletingaid=1
andaid=2
fail. Deletingaid=3
succeeds. The desgin is exactly as your question, 3 tables, not nullable columns, and FKs from (B->A, C->B, C->A).
– ypercubeᵀᴹ
Mar 2 '18 at 14:52
Are you sure the case with 3 tables (A, B, C) succeeds always?
– ypercubeᵀᴹ
Mar 2 '18 at 14:08
Are you sure the case with 3 tables (A, B, C) succeeds always?
– ypercubeᵀᴹ
Mar 2 '18 at 14:08
dbfiddle.uk 3 cases, some fail, some succeed
– ypercubeᵀᴹ
Mar 2 '18 at 14:24
dbfiddle.uk 3 cases, some fail, some succeed
– ypercubeᵀᴹ
Mar 2 '18 at 14:24
By 3 cases, are you talking about the 3 possible cases you can have with rows in this example? My assumption here was was 3 tables will all non-nullable fields, with rows that make use of the foreign keys.
– Matthias
Mar 2 '18 at 14:42
By 3 cases, are you talking about the 3 possible cases you can have with rows in this example? My assumption here was was 3 tables will all non-nullable fields, with rows that make use of the foreign keys.
– Matthias
Mar 2 '18 at 14:42
I'm trying to understand the general rule set though, without regard to the rows. On a logical level. Ultimately, I want to implement an algorithm that by just analysing the tables' structure can verify whether a delete will always be a success, or not (only succeeding under some conditions is a fail).
– Matthias
Mar 2 '18 at 14:44
I'm trying to understand the general rule set though, without regard to the rows. On a logical level. Ultimately, I want to implement an algorithm that by just analysing the tables' structure can verify whether a delete will always be a success, or not (only succeeding under some conditions is a fail).
– Matthias
Mar 2 '18 at 14:44
Yes, with 3 cases I meant the specific inserts. Deleting
aid=1
and aid=2
fail. Deleting aid=3
succeeds. The desgin is exactly as your question, 3 tables, not nullable columns, and FKs from (B->A, C->B, C->A).– ypercubeᵀᴹ
Mar 2 '18 at 14:52
Yes, with 3 cases I meant the specific inserts. Deleting
aid=1
and aid=2
fail. Deleting aid=3
succeeds. The desgin is exactly as your question, 3 tables, not nullable columns, and FKs from (B->A, C->B, C->A).– ypercubeᵀᴹ
Mar 2 '18 at 14:52
|
show 6 more comments
1 Answer
1
active
oldest
votes
I have managed to create a test case that at least for MySQL 5.6 demonstrates, for all intents and purposes, that the behaviour is undefined. Consider these 3 examples creating a "diamond"-shape between A, B, C and D.
Example 1
CREATE TABLE `a` (id INT UNSIGNED NOT NULL,
PRIMARY KEY (id)
) ENGINE = INNODB;
CREATE TABLE `b` (
id INT UNSIGNED NOT NULL,
a INT UNSIGNED NOT NULL,
PRIMARY KEY (id),
FOREIGN KEY (a) REFERENCES a (id) ON DELETE CASCADE
) ENGINE = INNODB;
CREATE TABLE `c` (
id INT UNSIGNED NOT NULL,
a INT UNSIGNED NOT NULL,
PRIMARY KEY (id),
FOREIGN KEY (a) REFERENCES a (id) ON DELETE CASCADE
) ENGINE = INNODB;
CREATE TABLE `d` (
id INT UNSIGNED NOT NULL,
b INT UNSIGNED NOT NULL,
c INT UNSIGNED NOT NULL,
PRIMARY KEY (id),
FOREIGN KEY (id) REFERENCES b (id) ON DELETE CASCADE,
FOREIGN KEY (id) REFERENCES c (id) ON DELETE CASCADE
) ENGINE = INNODB;
INSERT INTO a VALUES (1);
INSERT INTO b VALUES (1, 1);
INSERT INTO c VALUES (1, 1);
INSERT INTO d VALUES (1, 1, 1);
DELETE FROM a;
Delete from a is successful as expected, as all keys are CASCADE.
Example 2
CREATE TABLE `a` (
id INT UNSIGNED NOT NULL,
PRIMARY KEY (id)
) ENGINE = INNODB;
CREATE TABLE `b` (
id INT UNSIGNED NOT NULL,
a INT UNSIGNED NOT NULL,
PRIMARY KEY (id),
FOREIGN KEY (a) REFERENCES a (id) ON DELETE CASCADE
) ENGINE = INNODB;
CREATE TABLE `c` (
id INT UNSIGNED NOT NULL,
a INT UNSIGNED NOT NULL,
PRIMARY KEY (id),
FOREIGN KEY (a) REFERENCES a (id) ON DELETE CASCADE
) ENGINE = INNODB;
CREATE TABLE `d` (
id INT UNSIGNED NOT NULL,
b INT UNSIGNED NOT NULL,
c INT UNSIGNED NOT NULL,
PRIMARY KEY (id),
FOREIGN KEY (id) REFERENCES b (id) ON DELETE CASCADE,
FOREIGN KEY (id) REFERENCES c (id) ON DELETE RESTRICT
) ENGINE = INNODB;
INSERT INTO a VALUES (1);
INSERT INTO b VALUES (1, 1);
INSERT INTO c VALUES (1, 1);
INSERT INTO d VALUES (1, 1, 1);
DELETE FROM a;
Notice that d now has a RESTRICT to c. I would consider this case ambiguous as it forces you to consider which foreign key "wins". CASCADE or RESTICT, what is picked?
The result is that all rows are deleted.
Example 3
CREATE TABLE `a` (
id INT UNSIGNED NOT NULL,
PRIMARY KEY (id)
) ENGINE = INNODB;
CREATE TABLE `b` (
id INT UNSIGNED NOT NULL,
a INT UNSIGNED NOT NULL,
PRIMARY KEY (id),
FOREIGN KEY (a) REFERENCES a (id) ON DELETE CASCADE
) ENGINE = INNODB;
CREATE TABLE `c` (
id INT UNSIGNED NOT NULL,
a INT UNSIGNED NOT NULL,
PRIMARY KEY (id),
FOREIGN KEY (a) REFERENCES a (id) ON DELETE CASCADE
) ENGINE = INNODB;
CREATE TABLE `d` (
id INT UNSIGNED NOT NULL,
b INT UNSIGNED NOT NULL,
c INT UNSIGNED NOT NULL,
PRIMARY KEY (id),
FOREIGN KEY (id) REFERENCES b (id) ON DELETE RESTRICT,
FOREIGN KEY (id) REFERENCES c (id) ON DELETE CASCADE
) ENGINE = INNODB;
INSERT INTO a VALUES (1);
INSERT INTO b VALUES (1, 1);
INSERT INTO c VALUES (1, 1);
INSERT INTO d VALUES (1, 1, 1);
DELETE FROM a;
Notice that the only difference is the change of what foreign key is RESTRICT from d. This example however, fails with
Error Code: 1451
Cannot delete or update a parent row: a foreign key constraint fails (hello
.d
, CONSTRAINTd_ibfk_1
FOREIGN KEY (id
) REFERENCESb
(id
))
While logically, it's the same as Example 2. Without having looked at the source code of MySQL, I strongly suspect that the foreign keys are "applied" in lexical order based on their name. This is also the order the foreign keys are listed by mysqldump.
Without knowing whether what I'm testing here has a defined behaviour or not based on a higher logic, it's hard to know if this demonstrates either a bug, or simply the behaviour in MySQL.
Regardless, as it stands, this example shows that in practical terms I'd say that for all intents and purposes, when having mixed CASCADE and RESTRICT, the behaviour is undefined as it's not in any way sound that you should depend on the names given to foreign keys.
Another possible explaination is that deletion is performed by something similar to a depth-first traversal that fails whenever a RESTRICT is encountered. Traversal itself could possibly make use of a lexical order. Would need to look at source code. Still, as close to undefined as it gets in my opinion.
– Matthias
Mar 5 '18 at 10:11
add a comment |
Your Answer
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "182"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fdba.stackexchange.com%2fquestions%2f199171%2ftables-with-mixed-on-delete-cascade-and-on-delete-restrict-rule-set-with-recurs%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
I have managed to create a test case that at least for MySQL 5.6 demonstrates, for all intents and purposes, that the behaviour is undefined. Consider these 3 examples creating a "diamond"-shape between A, B, C and D.
Example 1
CREATE TABLE `a` (id INT UNSIGNED NOT NULL,
PRIMARY KEY (id)
) ENGINE = INNODB;
CREATE TABLE `b` (
id INT UNSIGNED NOT NULL,
a INT UNSIGNED NOT NULL,
PRIMARY KEY (id),
FOREIGN KEY (a) REFERENCES a (id) ON DELETE CASCADE
) ENGINE = INNODB;
CREATE TABLE `c` (
id INT UNSIGNED NOT NULL,
a INT UNSIGNED NOT NULL,
PRIMARY KEY (id),
FOREIGN KEY (a) REFERENCES a (id) ON DELETE CASCADE
) ENGINE = INNODB;
CREATE TABLE `d` (
id INT UNSIGNED NOT NULL,
b INT UNSIGNED NOT NULL,
c INT UNSIGNED NOT NULL,
PRIMARY KEY (id),
FOREIGN KEY (id) REFERENCES b (id) ON DELETE CASCADE,
FOREIGN KEY (id) REFERENCES c (id) ON DELETE CASCADE
) ENGINE = INNODB;
INSERT INTO a VALUES (1);
INSERT INTO b VALUES (1, 1);
INSERT INTO c VALUES (1, 1);
INSERT INTO d VALUES (1, 1, 1);
DELETE FROM a;
Delete from a is successful as expected, as all keys are CASCADE.
Example 2
CREATE TABLE `a` (
id INT UNSIGNED NOT NULL,
PRIMARY KEY (id)
) ENGINE = INNODB;
CREATE TABLE `b` (
id INT UNSIGNED NOT NULL,
a INT UNSIGNED NOT NULL,
PRIMARY KEY (id),
FOREIGN KEY (a) REFERENCES a (id) ON DELETE CASCADE
) ENGINE = INNODB;
CREATE TABLE `c` (
id INT UNSIGNED NOT NULL,
a INT UNSIGNED NOT NULL,
PRIMARY KEY (id),
FOREIGN KEY (a) REFERENCES a (id) ON DELETE CASCADE
) ENGINE = INNODB;
CREATE TABLE `d` (
id INT UNSIGNED NOT NULL,
b INT UNSIGNED NOT NULL,
c INT UNSIGNED NOT NULL,
PRIMARY KEY (id),
FOREIGN KEY (id) REFERENCES b (id) ON DELETE CASCADE,
FOREIGN KEY (id) REFERENCES c (id) ON DELETE RESTRICT
) ENGINE = INNODB;
INSERT INTO a VALUES (1);
INSERT INTO b VALUES (1, 1);
INSERT INTO c VALUES (1, 1);
INSERT INTO d VALUES (1, 1, 1);
DELETE FROM a;
Notice that d now has a RESTRICT to c. I would consider this case ambiguous as it forces you to consider which foreign key "wins". CASCADE or RESTICT, what is picked?
The result is that all rows are deleted.
Example 3
CREATE TABLE `a` (
id INT UNSIGNED NOT NULL,
PRIMARY KEY (id)
) ENGINE = INNODB;
CREATE TABLE `b` (
id INT UNSIGNED NOT NULL,
a INT UNSIGNED NOT NULL,
PRIMARY KEY (id),
FOREIGN KEY (a) REFERENCES a (id) ON DELETE CASCADE
) ENGINE = INNODB;
CREATE TABLE `c` (
id INT UNSIGNED NOT NULL,
a INT UNSIGNED NOT NULL,
PRIMARY KEY (id),
FOREIGN KEY (a) REFERENCES a (id) ON DELETE CASCADE
) ENGINE = INNODB;
CREATE TABLE `d` (
id INT UNSIGNED NOT NULL,
b INT UNSIGNED NOT NULL,
c INT UNSIGNED NOT NULL,
PRIMARY KEY (id),
FOREIGN KEY (id) REFERENCES b (id) ON DELETE RESTRICT,
FOREIGN KEY (id) REFERENCES c (id) ON DELETE CASCADE
) ENGINE = INNODB;
INSERT INTO a VALUES (1);
INSERT INTO b VALUES (1, 1);
INSERT INTO c VALUES (1, 1);
INSERT INTO d VALUES (1, 1, 1);
DELETE FROM a;
Notice that the only difference is the change of what foreign key is RESTRICT from d. This example however, fails with
Error Code: 1451
Cannot delete or update a parent row: a foreign key constraint fails (hello
.d
, CONSTRAINTd_ibfk_1
FOREIGN KEY (id
) REFERENCESb
(id
))
While logically, it's the same as Example 2. Without having looked at the source code of MySQL, I strongly suspect that the foreign keys are "applied" in lexical order based on their name. This is also the order the foreign keys are listed by mysqldump.
Without knowing whether what I'm testing here has a defined behaviour or not based on a higher logic, it's hard to know if this demonstrates either a bug, or simply the behaviour in MySQL.
Regardless, as it stands, this example shows that in practical terms I'd say that for all intents and purposes, when having mixed CASCADE and RESTRICT, the behaviour is undefined as it's not in any way sound that you should depend on the names given to foreign keys.
Another possible explaination is that deletion is performed by something similar to a depth-first traversal that fails whenever a RESTRICT is encountered. Traversal itself could possibly make use of a lexical order. Would need to look at source code. Still, as close to undefined as it gets in my opinion.
– Matthias
Mar 5 '18 at 10:11
add a comment |
I have managed to create a test case that at least for MySQL 5.6 demonstrates, for all intents and purposes, that the behaviour is undefined. Consider these 3 examples creating a "diamond"-shape between A, B, C and D.
Example 1
CREATE TABLE `a` (id INT UNSIGNED NOT NULL,
PRIMARY KEY (id)
) ENGINE = INNODB;
CREATE TABLE `b` (
id INT UNSIGNED NOT NULL,
a INT UNSIGNED NOT NULL,
PRIMARY KEY (id),
FOREIGN KEY (a) REFERENCES a (id) ON DELETE CASCADE
) ENGINE = INNODB;
CREATE TABLE `c` (
id INT UNSIGNED NOT NULL,
a INT UNSIGNED NOT NULL,
PRIMARY KEY (id),
FOREIGN KEY (a) REFERENCES a (id) ON DELETE CASCADE
) ENGINE = INNODB;
CREATE TABLE `d` (
id INT UNSIGNED NOT NULL,
b INT UNSIGNED NOT NULL,
c INT UNSIGNED NOT NULL,
PRIMARY KEY (id),
FOREIGN KEY (id) REFERENCES b (id) ON DELETE CASCADE,
FOREIGN KEY (id) REFERENCES c (id) ON DELETE CASCADE
) ENGINE = INNODB;
INSERT INTO a VALUES (1);
INSERT INTO b VALUES (1, 1);
INSERT INTO c VALUES (1, 1);
INSERT INTO d VALUES (1, 1, 1);
DELETE FROM a;
Delete from a is successful as expected, as all keys are CASCADE.
Example 2
CREATE TABLE `a` (
id INT UNSIGNED NOT NULL,
PRIMARY KEY (id)
) ENGINE = INNODB;
CREATE TABLE `b` (
id INT UNSIGNED NOT NULL,
a INT UNSIGNED NOT NULL,
PRIMARY KEY (id),
FOREIGN KEY (a) REFERENCES a (id) ON DELETE CASCADE
) ENGINE = INNODB;
CREATE TABLE `c` (
id INT UNSIGNED NOT NULL,
a INT UNSIGNED NOT NULL,
PRIMARY KEY (id),
FOREIGN KEY (a) REFERENCES a (id) ON DELETE CASCADE
) ENGINE = INNODB;
CREATE TABLE `d` (
id INT UNSIGNED NOT NULL,
b INT UNSIGNED NOT NULL,
c INT UNSIGNED NOT NULL,
PRIMARY KEY (id),
FOREIGN KEY (id) REFERENCES b (id) ON DELETE CASCADE,
FOREIGN KEY (id) REFERENCES c (id) ON DELETE RESTRICT
) ENGINE = INNODB;
INSERT INTO a VALUES (1);
INSERT INTO b VALUES (1, 1);
INSERT INTO c VALUES (1, 1);
INSERT INTO d VALUES (1, 1, 1);
DELETE FROM a;
Notice that d now has a RESTRICT to c. I would consider this case ambiguous as it forces you to consider which foreign key "wins". CASCADE or RESTICT, what is picked?
The result is that all rows are deleted.
Example 3
CREATE TABLE `a` (
id INT UNSIGNED NOT NULL,
PRIMARY KEY (id)
) ENGINE = INNODB;
CREATE TABLE `b` (
id INT UNSIGNED NOT NULL,
a INT UNSIGNED NOT NULL,
PRIMARY KEY (id),
FOREIGN KEY (a) REFERENCES a (id) ON DELETE CASCADE
) ENGINE = INNODB;
CREATE TABLE `c` (
id INT UNSIGNED NOT NULL,
a INT UNSIGNED NOT NULL,
PRIMARY KEY (id),
FOREIGN KEY (a) REFERENCES a (id) ON DELETE CASCADE
) ENGINE = INNODB;
CREATE TABLE `d` (
id INT UNSIGNED NOT NULL,
b INT UNSIGNED NOT NULL,
c INT UNSIGNED NOT NULL,
PRIMARY KEY (id),
FOREIGN KEY (id) REFERENCES b (id) ON DELETE RESTRICT,
FOREIGN KEY (id) REFERENCES c (id) ON DELETE CASCADE
) ENGINE = INNODB;
INSERT INTO a VALUES (1);
INSERT INTO b VALUES (1, 1);
INSERT INTO c VALUES (1, 1);
INSERT INTO d VALUES (1, 1, 1);
DELETE FROM a;
Notice that the only difference is the change of what foreign key is RESTRICT from d. This example however, fails with
Error Code: 1451
Cannot delete or update a parent row: a foreign key constraint fails (hello
.d
, CONSTRAINTd_ibfk_1
FOREIGN KEY (id
) REFERENCESb
(id
))
While logically, it's the same as Example 2. Without having looked at the source code of MySQL, I strongly suspect that the foreign keys are "applied" in lexical order based on their name. This is also the order the foreign keys are listed by mysqldump.
Without knowing whether what I'm testing here has a defined behaviour or not based on a higher logic, it's hard to know if this demonstrates either a bug, or simply the behaviour in MySQL.
Regardless, as it stands, this example shows that in practical terms I'd say that for all intents and purposes, when having mixed CASCADE and RESTRICT, the behaviour is undefined as it's not in any way sound that you should depend on the names given to foreign keys.
Another possible explaination is that deletion is performed by something similar to a depth-first traversal that fails whenever a RESTRICT is encountered. Traversal itself could possibly make use of a lexical order. Would need to look at source code. Still, as close to undefined as it gets in my opinion.
– Matthias
Mar 5 '18 at 10:11
add a comment |
I have managed to create a test case that at least for MySQL 5.6 demonstrates, for all intents and purposes, that the behaviour is undefined. Consider these 3 examples creating a "diamond"-shape between A, B, C and D.
Example 1
CREATE TABLE `a` (id INT UNSIGNED NOT NULL,
PRIMARY KEY (id)
) ENGINE = INNODB;
CREATE TABLE `b` (
id INT UNSIGNED NOT NULL,
a INT UNSIGNED NOT NULL,
PRIMARY KEY (id),
FOREIGN KEY (a) REFERENCES a (id) ON DELETE CASCADE
) ENGINE = INNODB;
CREATE TABLE `c` (
id INT UNSIGNED NOT NULL,
a INT UNSIGNED NOT NULL,
PRIMARY KEY (id),
FOREIGN KEY (a) REFERENCES a (id) ON DELETE CASCADE
) ENGINE = INNODB;
CREATE TABLE `d` (
id INT UNSIGNED NOT NULL,
b INT UNSIGNED NOT NULL,
c INT UNSIGNED NOT NULL,
PRIMARY KEY (id),
FOREIGN KEY (id) REFERENCES b (id) ON DELETE CASCADE,
FOREIGN KEY (id) REFERENCES c (id) ON DELETE CASCADE
) ENGINE = INNODB;
INSERT INTO a VALUES (1);
INSERT INTO b VALUES (1, 1);
INSERT INTO c VALUES (1, 1);
INSERT INTO d VALUES (1, 1, 1);
DELETE FROM a;
Delete from a is successful as expected, as all keys are CASCADE.
Example 2
CREATE TABLE `a` (
id INT UNSIGNED NOT NULL,
PRIMARY KEY (id)
) ENGINE = INNODB;
CREATE TABLE `b` (
id INT UNSIGNED NOT NULL,
a INT UNSIGNED NOT NULL,
PRIMARY KEY (id),
FOREIGN KEY (a) REFERENCES a (id) ON DELETE CASCADE
) ENGINE = INNODB;
CREATE TABLE `c` (
id INT UNSIGNED NOT NULL,
a INT UNSIGNED NOT NULL,
PRIMARY KEY (id),
FOREIGN KEY (a) REFERENCES a (id) ON DELETE CASCADE
) ENGINE = INNODB;
CREATE TABLE `d` (
id INT UNSIGNED NOT NULL,
b INT UNSIGNED NOT NULL,
c INT UNSIGNED NOT NULL,
PRIMARY KEY (id),
FOREIGN KEY (id) REFERENCES b (id) ON DELETE CASCADE,
FOREIGN KEY (id) REFERENCES c (id) ON DELETE RESTRICT
) ENGINE = INNODB;
INSERT INTO a VALUES (1);
INSERT INTO b VALUES (1, 1);
INSERT INTO c VALUES (1, 1);
INSERT INTO d VALUES (1, 1, 1);
DELETE FROM a;
Notice that d now has a RESTRICT to c. I would consider this case ambiguous as it forces you to consider which foreign key "wins". CASCADE or RESTICT, what is picked?
The result is that all rows are deleted.
Example 3
CREATE TABLE `a` (
id INT UNSIGNED NOT NULL,
PRIMARY KEY (id)
) ENGINE = INNODB;
CREATE TABLE `b` (
id INT UNSIGNED NOT NULL,
a INT UNSIGNED NOT NULL,
PRIMARY KEY (id),
FOREIGN KEY (a) REFERENCES a (id) ON DELETE CASCADE
) ENGINE = INNODB;
CREATE TABLE `c` (
id INT UNSIGNED NOT NULL,
a INT UNSIGNED NOT NULL,
PRIMARY KEY (id),
FOREIGN KEY (a) REFERENCES a (id) ON DELETE CASCADE
) ENGINE = INNODB;
CREATE TABLE `d` (
id INT UNSIGNED NOT NULL,
b INT UNSIGNED NOT NULL,
c INT UNSIGNED NOT NULL,
PRIMARY KEY (id),
FOREIGN KEY (id) REFERENCES b (id) ON DELETE RESTRICT,
FOREIGN KEY (id) REFERENCES c (id) ON DELETE CASCADE
) ENGINE = INNODB;
INSERT INTO a VALUES (1);
INSERT INTO b VALUES (1, 1);
INSERT INTO c VALUES (1, 1);
INSERT INTO d VALUES (1, 1, 1);
DELETE FROM a;
Notice that the only difference is the change of what foreign key is RESTRICT from d. This example however, fails with
Error Code: 1451
Cannot delete or update a parent row: a foreign key constraint fails (hello
.d
, CONSTRAINTd_ibfk_1
FOREIGN KEY (id
) REFERENCESb
(id
))
While logically, it's the same as Example 2. Without having looked at the source code of MySQL, I strongly suspect that the foreign keys are "applied" in lexical order based on their name. This is also the order the foreign keys are listed by mysqldump.
Without knowing whether what I'm testing here has a defined behaviour or not based on a higher logic, it's hard to know if this demonstrates either a bug, or simply the behaviour in MySQL.
Regardless, as it stands, this example shows that in practical terms I'd say that for all intents and purposes, when having mixed CASCADE and RESTRICT, the behaviour is undefined as it's not in any way sound that you should depend on the names given to foreign keys.
I have managed to create a test case that at least for MySQL 5.6 demonstrates, for all intents and purposes, that the behaviour is undefined. Consider these 3 examples creating a "diamond"-shape between A, B, C and D.
Example 1
CREATE TABLE `a` (id INT UNSIGNED NOT NULL,
PRIMARY KEY (id)
) ENGINE = INNODB;
CREATE TABLE `b` (
id INT UNSIGNED NOT NULL,
a INT UNSIGNED NOT NULL,
PRIMARY KEY (id),
FOREIGN KEY (a) REFERENCES a (id) ON DELETE CASCADE
) ENGINE = INNODB;
CREATE TABLE `c` (
id INT UNSIGNED NOT NULL,
a INT UNSIGNED NOT NULL,
PRIMARY KEY (id),
FOREIGN KEY (a) REFERENCES a (id) ON DELETE CASCADE
) ENGINE = INNODB;
CREATE TABLE `d` (
id INT UNSIGNED NOT NULL,
b INT UNSIGNED NOT NULL,
c INT UNSIGNED NOT NULL,
PRIMARY KEY (id),
FOREIGN KEY (id) REFERENCES b (id) ON DELETE CASCADE,
FOREIGN KEY (id) REFERENCES c (id) ON DELETE CASCADE
) ENGINE = INNODB;
INSERT INTO a VALUES (1);
INSERT INTO b VALUES (1, 1);
INSERT INTO c VALUES (1, 1);
INSERT INTO d VALUES (1, 1, 1);
DELETE FROM a;
Delete from a is successful as expected, as all keys are CASCADE.
Example 2
CREATE TABLE `a` (
id INT UNSIGNED NOT NULL,
PRIMARY KEY (id)
) ENGINE = INNODB;
CREATE TABLE `b` (
id INT UNSIGNED NOT NULL,
a INT UNSIGNED NOT NULL,
PRIMARY KEY (id),
FOREIGN KEY (a) REFERENCES a (id) ON DELETE CASCADE
) ENGINE = INNODB;
CREATE TABLE `c` (
id INT UNSIGNED NOT NULL,
a INT UNSIGNED NOT NULL,
PRIMARY KEY (id),
FOREIGN KEY (a) REFERENCES a (id) ON DELETE CASCADE
) ENGINE = INNODB;
CREATE TABLE `d` (
id INT UNSIGNED NOT NULL,
b INT UNSIGNED NOT NULL,
c INT UNSIGNED NOT NULL,
PRIMARY KEY (id),
FOREIGN KEY (id) REFERENCES b (id) ON DELETE CASCADE,
FOREIGN KEY (id) REFERENCES c (id) ON DELETE RESTRICT
) ENGINE = INNODB;
INSERT INTO a VALUES (1);
INSERT INTO b VALUES (1, 1);
INSERT INTO c VALUES (1, 1);
INSERT INTO d VALUES (1, 1, 1);
DELETE FROM a;
Notice that d now has a RESTRICT to c. I would consider this case ambiguous as it forces you to consider which foreign key "wins". CASCADE or RESTICT, what is picked?
The result is that all rows are deleted.
Example 3
CREATE TABLE `a` (
id INT UNSIGNED NOT NULL,
PRIMARY KEY (id)
) ENGINE = INNODB;
CREATE TABLE `b` (
id INT UNSIGNED NOT NULL,
a INT UNSIGNED NOT NULL,
PRIMARY KEY (id),
FOREIGN KEY (a) REFERENCES a (id) ON DELETE CASCADE
) ENGINE = INNODB;
CREATE TABLE `c` (
id INT UNSIGNED NOT NULL,
a INT UNSIGNED NOT NULL,
PRIMARY KEY (id),
FOREIGN KEY (a) REFERENCES a (id) ON DELETE CASCADE
) ENGINE = INNODB;
CREATE TABLE `d` (
id INT UNSIGNED NOT NULL,
b INT UNSIGNED NOT NULL,
c INT UNSIGNED NOT NULL,
PRIMARY KEY (id),
FOREIGN KEY (id) REFERENCES b (id) ON DELETE RESTRICT,
FOREIGN KEY (id) REFERENCES c (id) ON DELETE CASCADE
) ENGINE = INNODB;
INSERT INTO a VALUES (1);
INSERT INTO b VALUES (1, 1);
INSERT INTO c VALUES (1, 1);
INSERT INTO d VALUES (1, 1, 1);
DELETE FROM a;
Notice that the only difference is the change of what foreign key is RESTRICT from d. This example however, fails with
Error Code: 1451
Cannot delete or update a parent row: a foreign key constraint fails (hello
.d
, CONSTRAINTd_ibfk_1
FOREIGN KEY (id
) REFERENCESb
(id
))
While logically, it's the same as Example 2. Without having looked at the source code of MySQL, I strongly suspect that the foreign keys are "applied" in lexical order based on their name. This is also the order the foreign keys are listed by mysqldump.
Without knowing whether what I'm testing here has a defined behaviour or not based on a higher logic, it's hard to know if this demonstrates either a bug, or simply the behaviour in MySQL.
Regardless, as it stands, this example shows that in practical terms I'd say that for all intents and purposes, when having mixed CASCADE and RESTRICT, the behaviour is undefined as it's not in any way sound that you should depend on the names given to foreign keys.
answered Mar 5 '18 at 10:06
MatthiasMatthias
61
61
Another possible explaination is that deletion is performed by something similar to a depth-first traversal that fails whenever a RESTRICT is encountered. Traversal itself could possibly make use of a lexical order. Would need to look at source code. Still, as close to undefined as it gets in my opinion.
– Matthias
Mar 5 '18 at 10:11
add a comment |
Another possible explaination is that deletion is performed by something similar to a depth-first traversal that fails whenever a RESTRICT is encountered. Traversal itself could possibly make use of a lexical order. Would need to look at source code. Still, as close to undefined as it gets in my opinion.
– Matthias
Mar 5 '18 at 10:11
Another possible explaination is that deletion is performed by something similar to a depth-first traversal that fails whenever a RESTRICT is encountered. Traversal itself could possibly make use of a lexical order. Would need to look at source code. Still, as close to undefined as it gets in my opinion.
– Matthias
Mar 5 '18 at 10:11
Another possible explaination is that deletion is performed by something similar to a depth-first traversal that fails whenever a RESTRICT is encountered. Traversal itself could possibly make use of a lexical order. Would need to look at source code. Still, as close to undefined as it gets in my opinion.
– Matthias
Mar 5 '18 at 10:11
add a comment |
Thanks for contributing an answer to Database Administrators Stack Exchange!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fdba.stackexchange.com%2fquestions%2f199171%2ftables-with-mixed-on-delete-cascade-and-on-delete-restrict-rule-set-with-recurs%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Are you sure the case with 3 tables (A, B, C) succeeds always?
– ypercubeᵀᴹ
Mar 2 '18 at 14:08
dbfiddle.uk 3 cases, some fail, some succeed
– ypercubeᵀᴹ
Mar 2 '18 at 14:24
By 3 cases, are you talking about the 3 possible cases you can have with rows in this example? My assumption here was was 3 tables will all non-nullable fields, with rows that make use of the foreign keys.
– Matthias
Mar 2 '18 at 14:42
I'm trying to understand the general rule set though, without regard to the rows. On a logical level. Ultimately, I want to implement an algorithm that by just analysing the tables' structure can verify whether a delete will always be a success, or not (only succeeding under some conditions is a fail).
– Matthias
Mar 2 '18 at 14:44
Yes, with 3 cases I meant the specific inserts. Deleting
aid=1
andaid=2
fail. Deletingaid=3
succeeds. The desgin is exactly as your question, 3 tables, not nullable columns, and FKs from (B->A, C->B, C->A).– ypercubeᵀᴹ
Mar 2 '18 at 14:52