web-dev-qa-db-ja.com

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

ちょっと変わった問題があります。他のテーブルを参照するテーブルに外部キーを追加しようとしていますが、何らかの理由で失敗しています。 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
232
Zim

たぶんあなたのsourcecodes_tagsテーブルはあなたのsourcecodesテーブルにもう存在しないsourcecode_id値を含んでいます。あなたは最初にそれらを取り除く必要があります。

これらのIDを見つけることができるクエリは次のとおりです。

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

私は自分の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;
94
Prakash

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演算子よりもはるかに高速であることが知られています。また、作成や繰り返しもはるかに簡単です。

55
Ryan Ward

テーブルを切り捨ててから、FK制約を追加してみます。

私はこの解決策は少し厄介ですが、100%うまくいきます。しかし、これが問題に対処するための理想的な解決策ではないことに同意しますが、それが役立つことを願っています。

23

私にとって、この問題はちょっと違っていて、チェックして解決するのがとても簡単でした。

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

    SHOW TABLE STATUS WHERE Name =  't1';

    ALTER TABLE t1 ENGINE=InnoDB;
15
zmonteca

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

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

  2. 子列と親列は同じデータ型を持ちますか?

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

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

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

14
Michael Helwig

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

各child.columnがNULLであること、またはparent.idに存在する値を持つことを確認する必要があります。

そして今、私はnosが書いた声明を読み、それが彼が検証していることです。

14
fyrye

有効な外部キーではないため、0行目に無効な値があるため、MySQLは外部キー制約を設定できません。

次の手順に従ってください。

  1. FK制約を設定しようとしている列を削除します。

  2. 再度追加して、デフォルト値をNULLに設定してください。

  3. 外部キー制約をもう一度設定してみてください。

7
Milad

私は同じ問題を抱えていた、私は私のテーブルの行をチェックし、私は外部キーを定義したいというフィールドの値とのいくつかの非互換性があることがわかりました。私はそれらの値を修正し、再試行して問題を解決しました。

5
Mostafa -T

これを試して

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;
4
Carlo Guevarra

テーブルのすべてのデータを削除して、もう一度alterを実行します。できます。素晴らしいものではありませんが、それは多くの時間を節約します、特にあなたのアプリケーションはまだ顧客データなしで開発段階にあります。

4
VHanded

私はこれと全く同じ問題を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
mopsyd

Laravelを使用して外部キーリンクを作成しようとすると1452が発生する可能性がある場合、このエラーが発生していました。問題は、リンクテーブルにデータがないことでした。

例はこちらをご覧ください。 http://mstd.eu/index.php/2016/12/02/laravel-eloquent-integrity-constraint-violation-1452-foreign-key-制約/

2
twigg

両方のテーブルのデータを空にしてコマンドを実行します。それが動作します。

2
vijayrana

私はこの解決策を準備していました、そしてこの例は役に立つかもしれません。

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

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

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

参照先テーブルに参照先ローを最初に挿入してから外部キーを参照するローを挿入しても、エラーは発生しません。

お役に立てれば。

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を使用している場合は、外部キーチェックを有効にするのチェックを外してください。

としての例enter image description here

この解決策で問題が解決することを願っています:)

1
Fouad Mekkey

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

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

1

あなたはただ一つの質問に答える必要があります。

あなたのテーブルはすでにデータを保存していますか? (特にテーブルには外部キーが含まれていました。)

答えがイエスであれば、あなたがする必要がある唯一の事はすべてのレコードを削除することです、そしてあなたは自由にあなたのテーブルに外部キーを追加することができます。

削除指示:子(外部キーテーブルを含む)から親テーブルへ.

データ入力後に外部キーを追加できないのは、テーブルの矛盾が原因です。テーブルにデータが入力されているときに、新しい外部キーをどのように処理するのですか。

答えが「いいえ」の場合は、他の指示に従ってください。

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

これらのIDを取り除くのを助けるべきです。 nullsourcecode_idで許可されていない場合は、それらの行を削除するか、それらの欠損値をsourcecodesテーブルに追加します。

0
naXa

私は同じ問題を抱えていて解決策を見つけました。外部キーカラムにNOT NULLの代わりに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
akelec