Помилка 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)

EDIT: INі NOT INоператори, як відомо, набагато швидше, ніж JOINоператори, а також набагато простіше їх конструювати та повторювати.


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

@ Вінсент, якщо під батьківською таблицею ви маєте на увазі таблицю, на яку посилається, то так! Тому при виборі Cayetano ви отримуєте всі рядки, необхідні для оновлення / видалення з таблиці "дочірня" перед тим, як додати нове обмеження (FK). Після того, як всі вони вказують на значення у "else_table", тоді ви добре піти!
Armfoot

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
Іноді, якщо дані збільшують автоматичне підвищення ПК, це змушує вас усікати.
Франсуа Бретон

2
@ShankarDamodaran не впевнений, чому працює обрізка таблиці, але це рішення добре працювало для мене. Мені вдалося змусити свої стосунки працювати ... ДЯКУЮ!
MizAkita

@MizAkita працює, тому що видаляє рядки, які не мають відповідного значення в іншій таблиці, дозволяючи створювати нове обмеження. Якщо ви просто знайдете ці рядки та оновіть або видалите їх (наприклад , пропозиція Cayetano ), не потрібно видаляти інші рядки ...
Armfoot

@Armfoot - У мене виникла проблема під час додавання першого рядка до таблиці із зовнішнім ключем. Тож у мене не було рядків шукати.
Креветка

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

І тепер, коли я прочитав заяву, яку написав, це те, що він підтверджує.


14

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

  1. Чи є у вашому дочірньому стовпці значення, які не існують у батьківському стовпці (крім NULL, якщо дочірній стовпець є нульовим)

  2. Чи однакові та батьківські стовпці мають однаковий тип даних?

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

  4. І ця вирішила це для мене: чи обидві таблиці мають однакове порівняння?

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


7

Здається, що для рядка стовпця 0 є недійсним значенням, яке не є дійсним зовнішнім ключем, тому MySQL не може встановити для нього обмеження зовнішнього ключа.

Ви можете виконати наступні дії:

  1. Відкиньте стовпець, для якого ви намагалися встановити обмеження FK.

  2. Додайте його ще раз і встановіть його значення за замовчуванням як NULL.

  3. Спробуйте знову встановити обмеження для іноземного ключа.


5

З тією ж проблемою я перевірив рядки своїх таблиць і виявив, що існує якась несумісність зі значенням полів, які я хотів визначити зовнішнім ключем. Я виправив ці значення, спробував ще раз, і проблема була вирішена.


4

В кінцевому підсумку видаляю всі дані з моєї таблиці та запускаю змінити ще раз. Це працює. Не геніальний, але це економить багато часу, особливо ваша заявка все ще знаходиться на стадії розробки без будь-яких даних про клієнта.


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 та красномовного, спроба зробити посилання на зовнішній ключ призвела б до 1452. Проблема полягала у відсутності даних у пов'язаній таблиці.

Ознайомтесь із прикладом: http://mstd.eu/index.php/2016/12/02/laravel-eloquent-integrity-constraint-violation-1452-foreign-key-constraint/


1

Я готував це рішення, і цей приклад може допомогти.

У моїй базі даних є дві таблиці (електронна пошта та кредитна картка) з первинними ключами для їх ідентифікаторів. Інша таблиця (клієнт) посилається на ці ідентифікатори таблиць як зовнішні ключі. У мене є підстави мати електронний лист окрім даних клієнта.

Спочатку я вставляю дані про рядки для посилаються таблиць (електронна пошта, кредитна картка), потім ви отримуєте ідентифікатор для кожної, ці ідентифікатори потрібні в третій таблиці (клієнт).

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

Якщо ви вперше вставляєте посилання на рядки для посилаються таблиць, то в рядку, що посилається на іноземні ключі, помилка не виникає.

Сподіваюсь, це допомагає.


mysql> вставити в електронну пошту (електронну пошту) значення ('xxx@yyy.com'); mysql> вставити в ndtc (ndtc, рік, місяць) значення ('1111222233334444', '2000', '01'); mysql> вставити в клієнтські (nombres, apellidos, telefono, idNDTC, idEmail) значення ('myname', 'myapp', '5555555555', 1,1);
субстанціяMX

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.