So, I am getting:
Error Code: 1451. Cannot delete or update a parent row: a foreign key
constraint fails (playground.Person, CONSTRAINT sk_Person_Parent
FOREIGN KEY (parent_id) REFERENCES Person (id) ON DELETE CASCADE
ON UPDATE CASCADE)
This is the simple table, referencing itself:
CREATE TABLE IF NOT EXISTS Person (
id int not null primary key,
name varchar(100) not null,
parent_id int null,
CONSTRAINT `sk_Person_Parent`
FOREIGN KEY (parent_id)
REFERENCES Person (id)
ON DELETE CASCADE
ON UPDATE CASCADE
);
as you see, there is "ON UPDATE CASCADE".
I insert 4 simple rows in it:
INSERT INTO Person(id, name, parent_id)
VALUES
(1, 'vasko', NULL),
(2, 'asdas', 1),
(3, 'ivo', 1),
(4, 'anton', 3);
so I have
1 - vasko
2 - asdasd
3 - ivo
4 - anton.
When i delete by id 1, all the records get wiped, because of the ON DELETE CASCADE. However, if I try to execute
UPDATE Person
SET id=10
WHERE id=1;
I get the given error. Any ideas?
(I am expecting vasil's id to become 10, and the parent_id of the next 2 rows to be updated to 10)
It is limitation in Mysql:
If ON UPDATE CASCADE or ON UPDATE SET NULL recurses to update the same table it has previously updated during the cascade, it acts like RESTRICT. This means that you cannot use self-referential ON UPDATE CASCADE or ON UPDATE SET NULL operations.
reference here
Related
I've created two tables to do mappings between users. First for users and second for user-mappings. Deletion of users work well, but if I try to update the user id the foreign key constraints from the mapping table fail (without a helpful error output).
CREATE TABLE user (
id INT NOT NULL AUTO_INCREMENT,
name VARCHAR(55),
PRIMARY KEY (`id`)
);
CREATE TABLE user_map (
map_id INT NOT NULL AUTO_INCREMENT,
user_a INT,
user_b INT,
PRIMARY KEY (`map_id`),
UNIQUE KEY `one_way` (`user_a`,`user_b`),
UNIQUE KEY `other_way` (`user_b`,`user_a`),
CONSTRAINT `acc_connections_ibfk_1` FOREIGN KEY (`user_a`) REFERENCES `user` (`id`) ON UPDATE CASCADE ON DELETE CASCADE,
CONSTRAINT `acc_connections_ibfk_2` FOREIGN KEY (`user_b`) REFERENCES `user` (`id`) ON UPDATE CASCADE ON DELETE CASCADE
)
Example Data:
INSERT INTO user (name) VALUES ("User A");
INSERT INTO user_map (user_a,user_b) VALUES (1,1);
If I try to update the user id afterwards I get the following error:
Cannot add or update a child row: a foreign key constraint fails
(`test_db`.`user_map`, CONSTRAINT `user_map_ibfk_2`
FOREIGN KEY (`user_b`) REFERENCES `user` (`id`) ON DELETE CASCADE ON UPDATE CASCADE)
DB Fiddle (Demo)
Interestingly deleting the parent row (user table) succeeds without an error.
What am I doing wrong? I see no reason why this should fail.
I don't know if this is a bug or intended behavior.
As a workaround, if your version of MySql is 8.0.13+, which supports Functional Key Parts, you can use 1 UNIQUE KEY (to check the uniqueness of the combination of the 2 columns) instead of the 2 keys and the UPDATE statement will work:
CREATE TABLE IF NOT EXISTS user_map (
map_id INT NOT NULL AUTO_INCREMENT,
user_a INT,
user_b INT,
PRIMARY KEY (`map_id`),
UNIQUE KEY unk_users((LEAST(`user_a`,`user_b`)), (GREATEST(`user_a`,`user_b`))),
CONSTRAINT `acc_connections_ibfk_1` FOREIGN KEY (`user_a`) REFERENCES `user` (`id`) ON UPDATE CASCADE ON DELETE CASCADE,
CONSTRAINT `acc_connections_ibfk_2` FOREIGN KEY (`user_b`) REFERENCES `user` (`id`) ON UPDATE CASCADE ON DELETE CASCADE
);
See the demo.
In MySQL I want to update an ID-column of a table that is referenced in a foreign key constraint within that same table.
Example code:
CREATE TABLE A (
A_id int,
parent_A_id int,
PRIMARY KEY (A_id),
CONSTRAINT parent_A FOREIGN KEY (parent_A_id) REFERENCES A (A_id) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB;
INSERT INTO A VALUES (0, NULL), (1, 0);
Now I try to update the column A_id with
UPDATE A SET A_id = A_id + 1;
Unfortunately this throws an error:
Cannot delete or update a parent row: a foreign key constraint fails
I don't really understand why this fails and I can't find anything in the MySQL docs mentioning this not being allowed.
So, why does this not work?
And in the case that I don't just do a stupid mistake:
Is there any better way of doing such an update other than setting foreign_key_checks = 0 and doing everything by hand?
My problem with this would be that I'd like to use the ON UPDATE CASCADE to let the DB handle all foreign key updates for me.
I've created a SQLFiddle with the code shown below. The problem is that after the DELETE statement the associated credit_card record is supposed to be deleted as well.
CREATE TABLE person (
id BIGINT AUTO_INCREMENT PRIMARY KEY
);
CREATE TABLE credit_card (
id BIGINT AUTO_INCREMENT PRIMARY KEY
);
CREATE TABLE person_credit_card (
person_id BIGINT NOT NULL,
credit_card_id BIGINT NOT NULL UNIQUE, -- Please note that this is UNIQUE
PRIMARY KEY(person_id, credit_card_id),
CONSTRAINT fk__person_credit_card__person
FOREIGN KEY (person_id)
REFERENCES person(id),
KEY pkey (credit_card_id),
CONSTRAINT fk__person_credit_card__credit_card
FOREIGN KEY (credit_card_id)
REFERENCES credit_card(id)
ON DELETE CASCADE
ON UPDATE CASCADE
);
INSERT INTO person (id) VALUES (1);
INSERT INTO credit_card (id) VALUES (1);
INSERT INTO person_credit_card (person_id, credit_card_id) VALUES (1, 1);
DELETE FROM person_credit_card WHERE credit_card_id = 1;
I'm not sure why this is not working. With the UNIQUE constraint on the credit_card_id this is not possible:
+--------------------------------------+
| person_credit_card |
+--------------------------------------+
| person_id | credit_card_id |
+--------------------------------------+
| 1 | 1 |
+--------------------------------------+
| 2 | 1 |
+--------------------------------------+
So what am I doing wrong here and how can I make it work?
I also tried to e.g. delete a person and remove all his credit_card records (see this other SQLFiddle):
CREATE TABLE person (
id BIGINT AUTO_INCREMENT PRIMARY KEY
);
CREATE TABLE credit_card (
id BIGINT AUTO_INCREMENT PRIMARY KEY
);
CREATE TABLE person_credit_card (
person_id BIGINT NOT NULL,
credit_card_id BIGINT NOT NULL UNIQUE,
PRIMARY KEY(person_id, credit_card_id),
CONSTRAINT fk__person_credit_card__person
FOREIGN KEY (person_id)
REFERENCES person(id)
ON DELETE CASCADE
ON UPDATE CASCADE,
CONSTRAINT fk__person_credit_card__credit_card
FOREIGN KEY (credit_card_id)
REFERENCES credit_card(id)
ON DELETE CASCADE
ON UPDATE CASCADE
);
INSERT INTO person (id) VALUES (1);
INSERT INTO person (id) VALUES (2);
INSERT INTO credit_card (id) VALUES (1);
INSERT INTO credit_card (id) VALUES (2);
INSERT INTO credit_card (id) VALUES (3);
INSERT INTO person_credit_card (person_id, credit_card_id) VALUES (1, 1);
INSERT INTO person_credit_card (person_id, credit_card_id) VALUES (1, 2);
INSERT INTO person_credit_card (person_id, credit_card_id) VALUES (2, 3);
DELETE FROM person WHERE id = 1;
but the outcome is that only the resolution table is losing its entries but the credit_card records are still there.
From the documentation:
CASCADE: Delete or update the row from the parent table, and
automatically delete or update the matching rows in the child table.
Both ON DELETE CASCADE and ON UPDATE CASCADE are supported.
Deleting from person_credit_card won't cascade person nor credit_card.
Cascade works by deleting/updating records from tables that reference the record being deleted.
In other words, since person doesn't have a column with reference to person_credit_card, then it won't be deleted.
So, I am getting:
Error Code: 1451. Cannot delete or update a parent row: a foreign key
constraint fails (playground.Person, CONSTRAINT sk_Person_Parent
FOREIGN KEY (parent_id) REFERENCES Person (id) ON DELETE CASCADE
ON UPDATE CASCADE)
This is the simple table, referencing itself:
CREATE TABLE IF NOT EXISTS Person (
id int not null primary key,
name varchar(100) not null,
parent_id int null,
CONSTRAINT `sk_Person_Parent`
FOREIGN KEY (parent_id)
REFERENCES Person (id)
ON DELETE CASCADE
ON UPDATE CASCADE
);
as you see, there is "ON UPDATE CASCADE".
I insert 4 simple rows in it:
INSERT INTO Person(id, name, parent_id)
VALUES
(1, 'vasko', NULL),
(2, 'asdas', 1),
(3, 'ivo', 1),
(4, 'anton', 3);
so I have
1 - vasko
2 - asdasd
3 - ivo
4 - anton.
When i delete by id 1, all the records get wiped, because of the ON DELETE CASCADE. However, if I try to execute
UPDATE Person
SET id=10
WHERE id=1;
I get the given error. Any ideas?
(I am expecting vasil's id to become 10, and the parent_id of the next 2 rows to be updated to 10)
It is limitation in Mysql:
If ON UPDATE CASCADE or ON UPDATE SET NULL recurses to update the same table it has previously updated during the cascade, it acts like RESTRICT. This means that you cannot use self-referential ON UPDATE CASCADE or ON UPDATE SET NULL operations.
reference here
I have a table with a foreign key auto-referenced, like this:
CREATE TABLE user
(
id INT,
name VARCHAR(20),
ref INT,
PRIMARY KEY(id)
)ENGINE=InnoDB;
ALTER TABLE user
ADD FOREIGN KEY (ref) REFERENCES user(id)
ON DELETE RESTRICT ON UPDATE CASCADE;
Then, I insert values in the table:
INSERT INTO user
VALUES(1, "User1", NULL), (2, "User2", 1), (3, "User3", 1), (4, "User4", 3);
SELECT * FROM user;
And I update a user to check if, when I update the id of a user, then the FK is updated on cascade:
UPDATE user
SET id = 5
WHERE id = 1;
But I get this error:
ERROR 1451 (23000): Cannot delete or update a parent row: a foreign key constraint fails ('prueba'.'user', CONSTRAINT 'user_ibfk1' FOREIGN KEY ('ref') REFERENCES 'user' ('id') ON UPDATE CASCADE)
Can anyone say me what I'm doing wrong? Thank you.
see the dev document. Your self-referential "ON UPDATE CASCADE" acts like "ON UPDATE RESTRICT".
http://dev.mysql.com/doc/refman/5.5/en/innodb-foreign-key-constraints.html
If ON UPDATE CASCADE or ON UPDATE SET NULL recurses to update the same table it has previously updated during the cascade, it acts like RESTRICT. This means that you cannot use self-referential ON UPDATE CASCADE or ON UPDATE SET NULL operations. This is to prevent infinite loops resulting from cascaded updates. A self-referential ON DELETE SET NULL, on the other hand, is possible, as is a self-referential ON DELETE CASCADE. Cascading operations may not be nested more than 15 levels deep.