MySQLのエラー1452-子行を追加または更新できません:外部キー制約が失敗します


237

少し奇妙な問題が発生しています。別のテーブルを参照する外部キーを1つのテーブルに追加しようとしていますが、何らかの理由で失敗しています。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
エラーが発生する挿入/更新コマンドを投稿することもできますか?
Zed

64
この外部キーを追加すると、テーブルは空になりますか?
Zed

12
このクエリを実行して、実際のIDではないsourcecode_idがあるかどうかを確認してください。
ゼッド

11
Zedに感謝します。それは、テーブルの1つにデータが含まれていた問題でした。今考えてみると、存在しないアイテムを参照しているものがあったので失敗していたのは理にかなっていると思いますが、私はそれを想像していませんでした。ありがとう!
ジム、

2
テーブルが空の場合、なぜ失敗するのですか?
theblackpearl 2014年

回答:


226

おそらくsourcecodes_tagsテーブルに、テーブルにsourcecode_id存在しない値が含まれていsourcecodesます。最初にそれらを取り除く必要があります。

これらのIDを検索できるクエリは次のとおりです。

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)これらのIDを取り除くのに役立つはずです。または、nullで許可されていない場合はsourcecode_id、それらの行を削除するか、欠落している値をsourcecodesテーブルに追加します。
naXa 2016

同じことを考えてSELECT Tchild.id FROM Tchild INNER JOIN Tmain ON Tmain.id = Tchild.fk_id WHERE Tmain.id IS NULLいたのですが、何も返ってこないので、問題は別のところに!?
メロマン2017

ああ、これは私にとって問題でした。実行しようUPDATE `homestead`.`automations` SET `deleted_at`=NULL WHERE deleted_at IS NOT NULL;としていましたが、外部キーがまったく含まれていなかったため、混乱しました。しかし、私の連絡先テーブルにオートメーションテーブルが参照するいくつかのレコードが欠落していたという事実により、この「エラーコード:1452。子行を追加または更新できません:外部キー制約が失敗しました」がスローされました。
Ryan

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 2014年

5
@AbuSadatMohammedYasinいいえ、それはすべきではありません:「何が起こっているのか」という質問で、この回答は単にそれを説明しようとするものではありません。cs_alumnusが述べたように、より大きな問題があります。他のテーブルの別の値を参照するすべての新しい値(外部キーが行うべきこと)は何も指さず、矛盾した状態を作成する可能性があります。Cayetanoの簡潔で効果的な説明により、制約を作成する前に更新する必要のある値を見つけることができるため、存在するはずの値を返すはずのクエリに驚かされません!
Armfoot 2015年

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

@Vincent親テーブルとは、参照されているテーブルを意味する場合、そうです!したがって、Cayetanoの選択を使用すると、新しい制約(FK)を追加する前に、「子」テーブルから更新/削除する必要があるすべての行を取得できます。すべてが「another_table」の値を指すようになったら、準備完了です。
Armfoot 2015年

23

テーブルをトランケートしてから、FK制約を追加してみてください

このソリューションは少し厄介ですが、100%機能します。しかし、これは問題に対処するための理想的な解決策ではないことに同意しますが、それが役立つことを願っています。


4
すべてを切り捨てる必要はありません。「UPDATE sourcecodes_tags SET sourcecode_id = NULL WHERE sourcecode_id NOT IN(SELECT id FROM sourcecodes)」で十分です。または、「sourcecode_id」でnullが許可されていない場合は、それらの行を削除するか、欠落している値を「sourcecodes」テーブルに追加します。
Torben 2013

1
場合によっては、データが自動インクリメントPKをインクリメントすると、強制的に切り捨てられます。
フランソワ・ブルトン

2
@ShankarDamodaranは、なぜテーブルの切り捨てが機能するかわかりませんが、この解決策は私にとってうまくいきました。私は私の関係を機能させることができました...ありがとう!
MizAkita 14

@MizAkitaは、他のテーブルに対応する値がない行を削除し、新しい制約を作成できるため、機能します。それらの行を見つけて更新または削除する場合(Cayetanoの提案のように)、他の行を削​​除する必要はありません...
Armfoot

@Armfoot-外部キーを使用してテーブルに最初の行を追加すると、この問題が発生しました。そのため、検索する行がありませんでした。
2016年

16

私にとって、この問題は少し異なり、確認と解決が非常に簡単でした。

テーブルの両方がInnoDBであることを確認する必要があります。テーブルの1つ、つまり参照テーブルがMyISAMの場合、制約は失敗します。

    SHOW TABLE STATUS WHERE Name =  't1';

    ALTER TABLE t1 ENGINE=InnoDB;

14

これは、child.columnの値がすでに0で、parent.idの値が0でない場合に、外部キーをparent.idからchild.columnに設定するときにも発生します。

各child.columnがNULLであるか、parent.idに存在する値を持っていることを確認する必要があります

そして、私がnosが書いた声明を読んだ今、それは彼が検証しているものです。


14

今日も同じ問題がありました。私は4つのことをテストしましたが、そのうちのいくつかはすでにここで言及されています。

  1. 親列に存在しない子列の値はありますか(子列がnull可能の場合はNULL以外)

  2. 子列と親列のデータ型は同じですか?

  3. 参照している親列にインデックスはありますか?MySQLはパフォーマンス上の理由からこれを必要とするようです(http://dev.mysql.com/doc/refman/5.5/en/create-table-foreign-keys.html

  4. そして、これは私のためにそれを解決しました:両方のテーブルが同じ照合を持っていますか?

1つのテーブルはUTF-8で、もう1つはiso-somethingでした。それはうまくいきませんでした。ISOテーブルをUTF-8照合に変更した後、制約は問題なく追加できました。私の場合、phpMyAdminは、外部キー制約を作成するためのドロップダウンにiso-encodingで子テーブルを表示しませんでした。


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

私はこれとまったく同じ問題を3回ほど経験しました。いずれの場合も、1つ(または複数)のレコードが新しい外部キーに準拠していなかったことが原因です。キー自体を追加する前に、外部キーの構文制約に従うように既存のレコードを更新することができます。次の例では、通常、問題のあるレコードを分離する必要があります。

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


1

私はこのソリューションを準備しており、この例が役立つかもしれません。

私のデータベースには、IDの主キーを持つ2つのテーブル(emailとcredit_card)があります。別のテーブル(クライアント)は、このテーブルIDを外部キーとして参照します。メールをクライアントデータとは別にする理由があります。

最初に、参照されるテーブル(email、credit_card)の行データを挿入し、それぞれのIDを取得します。これらのIDは3番目のテーブル(クライアント)で必要です。

参照されるテーブルの行を最初に挿入しないと、外部キーを参照する3番目のテーブルに新しい行を挿入するときに、MySQLが対応できなくなります。

参照されるテーブルの参照される行を最初に挿入し、次に外部キーを参照する行を挿入した場合、エラーは発生しません。

お役に立てれば。


mysql>メールに挿入(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

値が他のテーブルにあることを確認してください。そうでない場合、割り当てられた対応する列でこのエラーが発生します。

したがって、割り当てられている列が別のテーブルの行IDに割り当てられている場合は、テーブルに行があることを確認してください。そうでない場合、このエラーが表示されます。


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);

これらのIDを取り除くのに役立つはずです。または、nullで許可されていない場合はsourcecode_id、それらの行を削除するか、欠落している値をsourcecodesテーブルに追加します。


0

私は同じ問題を抱えており、外部キー列NULLNOT 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を新しいテーブルにインポートして外部キーチェックを無効にしましたインポートの中断を無効にすると、すべてのデータが問題なく新しいテーブルに挿入され、古いテーブルが削除されます。

それは私のために働いた。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.