В MySQL - невозможно добавить или обновить дочернюю строку: ограничение внешнего ключа не выполняется

это, кажется, распространенная ошибка, но для жизни меня я не могу выяснить это.

у меня есть набор пользовательских таблиц InnoDB в MySQL, которые связаны друг с другом через внешний ключ; родитель user таблица и набор дочерних таблиц, в которых хранятся адреса электронной почты, действия и т. д. Они все привязаны к родителю user таблица с помощью внешнего ключа,uid, со всеми родительскими и дочерними ключами int(10).

все дочерние таблицы имеют uid значение с a ограничение внешнего ключа, указывающее на 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

6 ответов


Я решил мой'сбой ограничения внешнего ключа', добавив следующий код в начало кода SQL (это было для импорта значений в таблицу)

SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT;
SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS;
SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION;
SET NAMES utf8;
SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0;
SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0;
SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO';
SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0; 

затем добавьте этот код в конец файла

SET SQL_MODE=@OLD_SQL_MODE;
SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS;
SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS;
SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT;
SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS;
SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION;
SET SQL_NOTES=@OLD_SQL_NOTES; 

поскольку вы не дали определения таблиц, трудно догадаться. Но, похоже, вы пытаетесь изменить внешний ключ в дочерней таблице. 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):

Я столкнулся с той же проблемой при создании внешних ограничений на таблице. простой способ выйти из этой проблемы-сначала сделать резервную копию родительской и дочерней таблицы, а затем усечь дочернюю таблицу и снова попытаться установить связь. надеюсь, это решит проблему.


на несвязанной задаче я недавно поднял нашу базу данных MySQL в MySQL Workbench, и при просмотре отношений таблицы для вышеуказанных таблиц я заметил "дубликаты" и/или ложные отношения, которые я как-то пропустил раньше (они не появлялись в PHPMyAdmin FWIW). Устранение этих дополнительных связей немедленно прояснило проблему.


такая ошибка при обновлении может быть вызвана разница в наборе символов и сортировки, поэтому убедитесь, что они одинаковы для обеих таблиц.


надеюсь, что это поможет любому, кто имеет ту же ошибку при импорте данных CSV в связанные таблицы. В моем случае родительская таблица была в порядке, но я получил ошибку при импорте данных в дочернюю таблицу, содержащую внешний ключ. После временного удаления ограничения foregn key в дочерней таблице мне удалось импортировать данные и был удивлен, найдя некоторые значения в столбце FK, имеющие значения 0 (очевидно, это вызвало ошибку, так как родительская таблица не имела таких значения в столбце PK). Причина заключалась в том, что данные в моем столбце CSV, предшествующие столбцу FK, содержали запятые (которые я использовал в качестве делиметра поля). Изменение разделитель для моего CSV-файл решена проблема.