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
Zim
источник
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;
zmonteca
источник
14

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

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

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

fyrye
источник
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. Оно работает. Не блестящий, но это сэкономит много времени, особенно ваше приложение все еще находится в стадии разработки без каких-либо данных о клиентах.

VHanded
источник
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, но это всегда изолировало проблему для меня.

mopsyd
источник
2

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

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

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

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

Twigg
источник
1

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

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

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

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

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

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

SubstanceMX
источник
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таблицу.

naXa
источник
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 выполнил этот запрос!

akelec
источник
0

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

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

Шамаль Сабах
источник