MySQL - невозможно добавить или обновить дочернюю строку: ограничение внешнего ключа не выполняется
Это, кажется, обычная ошибка, но для жизни меня я не могу понять этого.
У меня есть набор пользовательских таблиц InnoDB в MySQL, связанных друг с другом через внешний ключ; родительская таблица user
и набор дочерних таблиц, которые хранят адреса электронной почты, действия и т.д. Все они привязаны к родительской таблице user
внешним ключом uid
со всеми родительскими и дочерними ключами int(10)
.
Все дочерние таблицы имеют значение uid
с ограничением внешнего ключа, указывающим на user.uid
, и установите ON DELETE CASCADE
и ON UPDATE CASCADE
.
Когда я удаляю пользователя из user
, все дочерние ограниченные записи удаляются. Однако, когда я пытаюсь обновить значение user.uid
, это приводит к следующей ошибке, а не к каскадированию изменения uid
дочерних таблиц:
#1452 - Cannot add or update a child row: a foreign key constraint fails (`accounts`.`user_email`, CONSTRAINT `user_email_ibfk_2` FOREIGN KEY (`uid`) REFERENCES `user` (`uid`) ON DELETE CASCADE ON UPDATE CASCADE)
У меня такое чувство, что я должен упустить что-то очевидное здесь. Удаление ограничения ключа с помощью user_email
и попытка обновления значения в user
приводит к той же ошибке, но для следующей дочерней таблицы user
в алфавитном порядке, поэтому я не верю, что это ошибка, связанная с таблицей.
EDIT:
Добавление результатов из SHOW ENGINE INNODB STATUS
:
------------------------
LATEST FOREIGN KEY ERROR
------------------------
121018 22:35:41 Transaction:
TRANSACTION 0 5564387, ACTIVE 0 sec, process no 1619, OS thread id 2957499248 updating or deleting, thread declared inside InnoDB 499
mysql tables in use 1, locked 1
17 lock struct(s), heap size 2496, 9 row lock(s), undo log entries 2
MySQL thread id 3435659, query id 24068634 localhost root Updating
UPDATE `accounts`.`user` SET `uid` = '1' WHERE `user`.`uid` = 306
Foreign key constraint fails for table `accounts`.`user_email`:
,
CONSTRAINT `user_email_ibfk_2` FOREIGN KEY (`uid`) REFERENCES `user` (`uid`) ON DELETE CASCADE ON UPDATE CASCADE
Trying to add in child table, in index `uid` tuple:
DATA TUPLE: 2 fields;
...
A bunch of hex code
But in parent table `accounts`.`user`, in index `PRIMARY`,
the closest match we can find is record:
...
A bunch of hex code
Ответы
Ответ 1
По несвязанной задаче я недавно поднял нашу базу данных MySQL в MySQL Workbench, а при просмотре табличных отношений для приведенных выше таблиц, я замеченные "дубликаты" и/или ложные отношения, которые я как-то пропустил раньше (они не появлялись в PHPMyAdmin FWIW). Удаление этих дополнительных отношений немедленно устранило проблему.
Ответ 2
Я решил, что мои проблемы с ограничениями внешнего ключа не удались, добавив следующий код в начало кода SQL (это было для импорта значений в таблицу)
SET @[email protected]@CHARACTER_SET_CLIENT;
SET @[email protected]@CHARACTER_SET_RESULTS;
SET @[email protected]@COLLATION_CONNECTION;
SET NAMES utf8;
SET @[email protected]@UNIQUE_CHECKS, UNIQUE_CHECKS=0;
SET @[email protected]@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0;
SET @[email protected]@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO';
SET @[email protected]@SQL_NOTES, SQL_NOTES=0;
Затем добавление этого кода в конец файла
SET [email protected]_SQL_MODE;
SET [email protected]_FOREIGN_KEY_CHECKS;
SET [email protected]_UNIQUE_CHECKS;
SET [email protected]_CHARACTER_SET_CLIENT;
SET [email protected]_CHARACTER_SET_RESULTS;
SET [email protected]_COLLATION_CONNECTION;
SET [email protected]_SQL_NOTES;
Ответ 3
Поскольку вы не указали определения таблиц, трудно догадаться. Но похоже, что вы пытаетесь изменить внешний ключ в дочерней таблице. AFAIK, это незаконно, вы можете изменить его из родительского, но не дочерней таблицы.
Рассмотрим следующий пример:
CREATE TABLE parent (
parent_id INT NOT NULL,
parent_data int,
PRIMARY KEY (parent_id)
) ENGINE=INNODB;
CREATE TABLE child1 (
child1_id INT,
child1_data INT,
fk_parent_id INT,
INDEX par_ind1 (fk_parent_id),
FOREIGN KEY (fk_parent_id)
REFERENCES parent(parent_id)
ON DELETE CASCADE
ON UPDATE CASCADE
) ENGINE=INNODB;
CREATE TABLE child2 (
child2_id INT,
child2_data INT,
fk_parent_id INT,
INDEX par_ind2 (fk_parent_id),
FOREIGN KEY (fk_parent_id)
REFERENCES parent(parent_id)
ON DELETE CASCADE
ON UPDATE CASCADE
) ENGINE=INNODB;
INSERT INTO parent
(parent_id, parent_data)
VALUES
(1, 11),
(2, 12);
INSERT INTO child1
(child1_id, child1_data, fk_parent_id)
VALUES
(101, 1001, 1),
(102, 1002, 1),
(103, 1003, 1),
(104, 1004, 2),
(105, 1005, 2);
INSERT INTO child2
(child2_id, child2_data, fk_parent_id)
VALUES
(106, 1006, 1),
(107, 1007, 1),
(108, 1008, 1),
(109, 1009, 2),
(110, 1010, 2);
Тогда это разрешено:
UPDATE parent
SET parent_id = 3 WHERE parent_id = 2;
SELECT * FROM parent;
SELECT * FROM child1;
SELECT * FROM child2;
Но это не так, потому что он изменяет родительский fk из дочерней таблицы:
UPDATE child1
SET fk_parent_id = 4 WHERE fk_parent_id = 1;
Он получает ошибку, очень похожую на вашу ошибку:
Cannot add or update a child row: a foreign key constraint fails (`db_2_b43a7`.`child1`, CONSTRAINT `child1_ibfk_1` FOREIGN KEY (`fk_parent_id`) REFERENCES `parent` (`parent_id`) ON DELETE CASCADE ON UPDATE CASCADE):
Ответ 4
Я столкнулся с такой же проблемой, создавая внешние ограничения для таблицы. простой способ выйти из этой проблемы - сначала взять резервную копию родительской и дочерней таблиц, а затем обрезать дочернюю таблицу и снова попытаться установить отношение. надеюсь, что это решит проблему.
Ответ 5
Такая ошибка при обновлении может быть вызвана различием в наборе символов и сопоставлении, поэтому убедитесь, что они одинаковы для обеих таблиц.
Ответ 6
Надеюсь, это поможет любому, кто имеет ту же ошибку, при импорте CSV-данных в связанные таблицы. В моем случае родительская таблица была в порядке, но я получил ошибку при импорте данных в дочернюю таблицу, содержащую внешний ключ. После временного удаления ограничения ключа foregn на дочерней таблице мне удалось импортировать данные и был удивлен, чтобы найти некоторые из значений в столбце FK со значениями 0 (очевидно, это вызвало ошибку, поскольку родительская таблица не имела такие значения в столбце PK). Дело в том, что данные в моей колонке CSV, предшествующие колонке FK, содержали запятые (которые я использовал в качестве полевого делиметра). Изменение разделителя для моего файла CSV решило проблему.