Mysql ошибка 1452 - Не удается добавить или обновить дочернюю строку: ограничение внешнего ключа не удается


237

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

Я сделал SHOW CREATE TABLEзапрос к обеим таблицам, sourcecodes_tagsтаблица с внешним ключом, sourcecodesэто ссылочная таблица.

CREATE TABLE `sourcecodes` (
 `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
 `user_id` int(11) unsigned NOT NULL,
 `language_id` int(11) unsigned NOT NULL,
 `category_id` int(11) unsigned NOT NULL,
 `title` varchar(40) CHARACTER SET utf8 NOT NULL,
 `description` text CHARACTER SET utf8 NOT NULL,
 `views` int(11) unsigned NOT NULL,
 `downloads` int(11) unsigned NOT NULL,
 `time_posted` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
 PRIMARY KEY (`id`),
 KEY `user_id` (`user_id`),
 KEY `language_id` (`language_id`),
 KEY `category_id` (`category_id`),
 CONSTRAINT `sourcecodes_ibfk_3` FOREIGN KEY (`language_id`) REFERENCES `languages` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
 CONSTRAINT `sourcecodes_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
 CONSTRAINT `sourcecodes_ibfk_2` FOREIGN KEY (`category_id`) REFERENCES `categories` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=latin1

CREATE TABLE `sourcecodes_tags` (
 `sourcecode_id` int(11) unsigned NOT NULL,
 `tag_id` int(11) unsigned NOT NULL,
 KEY `sourcecode_id` (`sourcecode_id`),
 KEY `tag_id` (`tag_id`),
 CONSTRAINT `sourcecodes_tags_ibfk_1` FOREIGN KEY (`tag_id`) REFERENCES `tags` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=latin1

Это код, который генерирует ошибку:

ALTER TABLE sourcecodes_tags ADD FOREIGN KEY (sourcecode_id) REFERENCES sourcecodes (id) ON DELETE CASCADE ON UPDATE CASCADE

2
Не могли бы вы также опубликовать команду вставки / обновления, которая приводит к ошибке?
— Зед

64
ваши таблицы пустые, когда вы добавляете этот внешний ключ?
— Зед

12
попробуйте выполнить этот запрос, чтобы увидеть, есть ли какой-либо sourcecode_id, который не является реальным идентификатором: SELECT sourcecode_id FROM sourcecodes_tags WHERE sourcecode_id NOT IN (SELECT id FROM sourcecodes AS tmp);
— Зед

11
Спасибо, Зед, это была проблема, в одной из таблиц были данные. Думая об этом сейчас, имеет смысл, что он терпел неудачу, потому что были вещи, которые ссылались на несуществующие элементы, но я бы никогда не догадался об этом. Спасибо!
— Зим

2
Почему не получается, если таблица пуста?
— theblackpearl

Ответы:


226

Вполне вероятно, что ваша sourcecodes_tagsтаблица содержит sourcecode_idзначения, которых больше нет в вашей sourcecodesтаблице. Вы должны сначала избавиться от них.

Вот запрос, который может найти эти идентификаторы:

SELECT DISTINCT sourcecode_id FROM 
   sourcecodes_tags tags LEFT JOIN sourcecodes sc ON tags.sourcecode_id=sc.id 
WHERE sc.id IS NULL;

UPDATE sourcecodes_tags SET sourcecode_id = NULL WHERE sourcecode_id NOT IN (SELECT id FROM sourcecodes)должен помочь избавиться от этих идентификаторов. Или, если nullэто не разрешено sourcecode_id, удалите эти строки или добавьте отсутствующие значения в sourcecodesтаблицу.
— naXa

Я думал так же, но для меня SELECT Tchild.id FROM Tchild INNER JOIN Tmain ON Tmain.id = Tchild.fk_id WHERE Tmain.id IS NULLничего не возвращается, поэтому проблема в другом месте!
— Меломан

Ах, это была проблема для меня. Я пытался бежать UPDATE `homestead`.`automations` SET `deleted_at`=NULL WHERE deleted_at IS NOT NULL;, который вообще не включал внешний ключ, поэтому я был сбит с толку. Но тот факт, что в моей таблице контактов отсутствовали некоторые записи, на которые ссылалась таблица автоматизации, привел к появлению этого «кода ошибки: 1452. Невозможно добавить или обновить дочернюю строку: ограничение внешнего ключа не выполнено».
— Райан

99

У меня была та же проблема с моей базой данных MySQL, но, наконец, я получил решение, которое сработало для меня.
Поскольку в моей таблице все было нормально с точки зрения mysql (обе таблицы должны использовать движок InnoDB, а тип данных каждого столбца должен быть одного типа, который принимает участие в ограничении внешнего ключа).
Единственное, что я сделал, - отключил проверку внешнего ключа, а затем включил ее после выполнения операции с внешним ключом.
Шаги, которые я предпринял:

SET foreign_key_checks = 0;
alter table tblUsedDestination add constraint f_operatorId foreign key(iOperatorId) references tblOperators (iOperatorId); Query
OK, 8 rows affected (0.23 sec) Records: 8  Duplicates: 0  Warnings: 0
SET foreign_key_checks = 1;

49
Foreign_key_checks есть по причине. Если вы не можете добавить внешний ключ, потому что он нарушает ограничение, вы должны сначала исправить данные. Отключение проверок и добавление ключа оставит вас в несогласованном состоянии. Проверка внешнего ключа добавляет накладные расходы, если вы не хотите их использовать, используйте вместо этого myisam.
— cs_alumnus

5
@AbuSadatMohammedYasin нет, это не должно: вопрос задан «что происходит», и этот ответ просто не пытается объяснить это. Как уже упоминалось cs_alumnus, есть большая проблема: все новые значения , которые должны быть ссылающимися другое значение в другой таблице ( в качестве внешнего ключа должны делать) могут указывать ничего, создавая несогласованное состояние. Краткое и эффективное объяснение Cayetano позволяет вам найти, какие значения вы должны обновить, прежде чем создавать ограничение, поэтому вы не будете удивлены запросами, которые должны возвращать значения, которые должны существовать!
— Armfoot

55

Используйте , NOT INчтобы найти , где ограничения сдерживая :

SELECT column FROM table WHERE column NOT IN 
(SELECT intended_foreign_key FROM another_table)

Итак, более конкретно:

SELECT sourcecode_id FROM sourcecodes_tags WHERE sourcecode_id NOT IN 
(SELECT id FROM sourcecodes)

РЕДАКТИРОВАТЬ: INи NOT INоператоры, как известно, намного быстрее, чем JOINоператоры, а также гораздо проще построить и повторить.


1
Итак, если я правильно понимаю, мы можем добавить внешний ключ в таблицу, в которой уже есть данные, но только если для каждой строки в родительской таблице существует дочерняя строка? Если для каждой строки в родительской таблице нет дочерних строк (что и обнаруживает ваш запрос), сценарий внешнего ключа завершится неудачно.
— Винсент

@ Vincent, если под родительской таблицей вы имеете в виду таблицу, на которую ссылаются, то да! Поэтому с помощью выбора Cayetano вы получаете все строки, которые необходимо обновить / удалить из вашей «дочерней» таблицы, прежде чем добавлять новое ограничение (FK). Как только они все указывают на значения в "another_table", тогда вы готовы!
— Армфут

23

Обрежьте таблицы и попробуйте добавить ограничение FK .

Я знаю, что это решение немного неудобно, но оно работает на 100%. Но я согласен, что это не идеальное решение для решения проблемы, но я надеюсь, что это поможет.


4
Не нужно усекать все. "UPDATE sourcecodes_tags SET sourcecode_id = NULL WHERE sourcecode_id NOT IN (SELECT id FROM sourcecodes)" должно быть достаточно. Или, если null не разрешен в «sourcecode_id», то удалите эти строки или добавьте эти пропущенные значения в таблицу «sourcecodes».
— Торбен

1
Иногда, если данные увеличивают автоинкремент PK, это заставляет вас усекаться.
— Франсуа Бретон

2
@ShankarDamodaran не уверен, почему усечение таблицы работает, но это решение хорошо сработало для меня. Я смог заставить мои отношения работать ... СПАСИБО!
— MizAkita

@MizAkita работает, потому что удаляет строки, которые не имеют соответствующего значения в другой таблице, позволяя создать новое ограничение. Если вы просто найдете эти строки и обновите или удалите их (как совет Кайетано ), вам не нужно удалять другие строки ...
— Armfoot

@Armfoot - у меня была эта проблема при добавлении первой строки в таблицу с внешним ключом. Поэтому у меня не было строк для поиска.
— Krewetka

16

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

Вы должны убедиться, что ОБА из ваших таблиц InnoDB. Если одна из таблиц, а именно справочная таблица, является MyISAM, ограничение не будет выполнено.

    SHOW TABLE STATUS WHERE Name =  't1';

    ALTER TABLE t1 ENGINE=InnoDB;

14

Это также происходит при установке внешнего ключа для parent.id для child.column, если child.column уже имеет значение 0, а значение parent.id не равно 0

Вы должны убедиться, что каждый child.column имеет значение NULL или имеет значение, которое существует в parent.id

И теперь, когда я прочитал заявление, которое написал nos, это то, что он проверяет.


14

У меня была такая же проблема сегодня. Я проверил четыре вещи, некоторые из которых уже упоминались здесь:

  1. Есть ли какие-либо значения в вашем дочернем столбце, которых нет в родительском столбце (кроме NULL, если дочерний столбец обнуляется)

  2. У дочерних и родительских столбцов одинаковый тип данных?

  3. Есть ли индекс родительского столбца, на который вы ссылаетесь? MySQL, кажется, требует этого по соображениям производительности ( http://dev.mysql.com/doc/refman/5.5/en/create-table-foreign-keys.html )

  4. И этот решил для меня: у обеих таблиц одинаковое сопоставление?

У меня был один стол в UTF-8, а другой в iso-что-то. Это не сработало. После изменения iso-таблицы на сопоставление UTF-8 ограничения могут быть добавлены без проблем. В моем случае phpMyAdmin даже не отображал дочернюю таблицу в iso-кодировке в раскрывающемся списке для создания ограничения внешнего ключа.


7

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

Вы можете выполнить следующие действия:

  1. Удалите столбец, для которого вы пытались установить ограничение FK.

  2. Добавьте его снова и установите его значение по умолчанию как NULL.

  3. Попробуйте снова установить для него ограничение внешнего ключа.


5

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


4

В итоге я удаляю все данные в моей таблице и снова запускаю alter. Оно работает. Не блестящий, но это сэкономит много времени, особенно ваше приложение все еще находится в стадии разработки без каких-либо данных о клиентах.


4

попробуй это

SET foreign_key_checks = 0;

ALTER TABLE sourcecodes_tags ADD FOREIGN KEY (sourcecode_id) REFERENCES sourcecodes (id) ON DELETE CASCADE ON UPDATE CASCADE

SET foreign_key_checks = 1;

2

У меня была такая же проблема примерно три раза. В каждом случае это было потому, что одна (или более) из моих записей не соответствовала новому внешнему ключу. Возможно, вы захотите обновить существующие записи в соответствии с синтаксическими ограничениями внешнего ключа, прежде чем пытаться добавить сам ключ. Следующий пример должен обычно изолировать записи о проблемах:

SELECT * FROM (tablename)
    WHERE (candidate key) <> (proposed foreign key value) 
        AND (candidate key) <> (next proposed foreign key value)

повторите AND (candidate key) <> (next proposed foreign key value)в вашем запросе для каждого значения во внешнем ключе.

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


2

Очистите данные обеих таблиц и выполните команду. Это сработает.


VHanded дал тот же ответ 3 года назад. Будем надеяться, что в таблицах не было важных данных ...
— xlecoustillier

2

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

Пожалуйста, см. Здесь для примера: http://mstd.eu/index.php/2016/12/02/laravel-eloquent-integrity-constraint-violation-1452-foreign-key-constraint/


1

Я готовил это решение, и этот пример может помочь.

В моей базе данных есть две таблицы (email и credit_card) с первичными ключами для их идентификаторов. Другая таблица (клиент) ссылается на идентификаторы этой таблицы как внешние ключи. У меня есть причина, чтобы иметь электронную почту отдельно от данных клиента.

Сначала я вставляю данные строки для ссылочных таблиц (электронная почта, credit_card), затем вы получаете идентификатор для каждой, эти идентификаторы необходимы в третьей таблице (клиент).

Если вы не вставите сначала строки в ссылочных таблицах, MySQL не сможет установить соответствия, когда вы вставите новую строку в третью таблицу, которая ссылается на внешние ключи.

Если сначала вставить ссылочные строки для ссылочных таблиц, то в строке, которая ссылается на внешние ключи, ошибки не возникает.

Надеюсь это поможет.


mysql> вставить в email (email) значения ('xxx@yyy.com'); mysql> вставить в значения ndtc (ndtc, year, month) ('1111222233334444', '2000', '01'); mysql> вставка в значения клиентов (nombres, apellidos, telefono, idNDTC, idEmail) («myname», «myapp», «5555555555», 1,1);
— SubstanceMX

1

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

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


1

Вы можете попробовать этот пример

 START TRANSACTION;
 SET foreign_key_checks = 0;
 ALTER TABLE `job_definers` ADD CONSTRAINT `job_cities_foreign` FOREIGN KEY 
 (`job_cities`) REFERENCES `drop_down_lists`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
 SET foreign_key_checks = 1;
 COMMIT;

Примечание: если вы используете phpmyadmin, просто снимите флажок Включить проверку внешнего ключа

как пример введите описание изображения здесь

надеюсь, что это решение решить вашу проблему :)


1

Вам просто нужно ответить на один вопрос:

Ваша таблица уже хранит данные? (Особенно в таблицу включен внешний ключ.)

Если ответ «да», то единственное, что вам нужно сделать, это удалить все записи, тогда вы можете добавить любой внешний ключ в вашу таблицу.

Инструкция удаления: от дочерней (которая включает в себя таблицу внешнего ключа) до родительской таблицы.

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

Если ответ «нет», следуйте другим инструкциям.


0
UPDATE sourcecodes_tags
SET sourcecode_id = NULL
WHERE sourcecode_id NOT IN (
  SELECT id FROM sourcecodes);

должен помочь избавиться от этих идентификаторов. Или, если nullэто не разрешено sourcecode_id, удалите эти строки или добавьте отсутствующие значения в sourcecodesтаблицу.


0

У меня была такая же проблема и я нашел решение, разместив NULLвместо NOT NULLстолбца внешнего ключа. Вот запрос:

ALTER TABLE `db`.`table1`
ADD COLUMN `col_table2_fk` INT UNSIGNED NULL,
ADD INDEX `col_table2_fk_idx` (`col_table2_fk` ASC),
ADD CONSTRAINT `col_table2_fk1`
FOREIGN KEY (`col_table2_fk`)
REFERENCES `db`.`table2` (`table2_id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION;

MySQL выполнил этот запрос!


0

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

Это сработало для меня.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.