親行を削除または更新できません:外部キー制約が失敗します


170

行うとき:

DELETE FROM `jobs` WHERE `job_id` =1 LIMIT 1 

エラー:

#1451 - Cannot delete or update a parent row: a foreign key constraint fails 
(paymesomething.advertisers, CONSTRAINT advertisers_ibfk_1 FOREIGN KEY 
(advertiser_id) REFERENCES jobs (advertiser_id))

これが私のテーブルです:

CREATE TABLE IF NOT EXISTS `advertisers` (
  `advertiser_id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(255) NOT NULL,
  `password` char(32) NOT NULL,
  `email` varchar(128) NOT NULL,
  `address` varchar(255) NOT NULL,
  `phone` varchar(255) NOT NULL,
  `fax` varchar(255) NOT NULL,
  `session_token` char(30) NOT NULL,
  PRIMARY KEY (`advertiser_id`),
  UNIQUE KEY `email` (`email`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 AUTO_INCREMENT=2 ;


INSERT INTO `advertisers` (`advertiser_id`, `name`, `password`, `email`, `address`, `phone`, `fax`, `session_token`) VALUES
(1, 'TEST COMPANY', '', '', '', '', '', '');

CREATE TABLE IF NOT EXISTS `jobs` (
  `job_id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `advertiser_id` int(11) unsigned NOT NULL,
  `name` varchar(255) NOT NULL,
  `shortdesc` varchar(255) NOT NULL,
  `longdesc` text NOT NULL,
  `address` varchar(255) NOT NULL,
  `time_added` int(11) NOT NULL,
  `active` tinyint(1) NOT NULL,
  `moderated` tinyint(1) NOT NULL,
  PRIMARY KEY (`job_id`),
  KEY `advertiser_id` (`advertiser_id`,`active`,`moderated`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 AUTO_INCREMENT=2 ;


INSERT INTO `jobs` (`job_id`, `advertiser_id`, `name`, `shortdesc`, `longdesc`, `address`, `active`, `moderated`) VALUES
(1, 1, 'TEST', 'TESTTEST', 'TESTTESTES', '', 0, 0);

ALTER TABLE `advertisers`
  ADD CONSTRAINT `advertisers_ibfk_1` FOREIGN KEY (`advertiser_id`) REFERENCES `jobs` (`advertiser_id`);

回答:


108

そのまま、それが参照する求人テーブルの行を削除する前に、広告主テーブルから行を削除する必要があります。この:

ALTER TABLE `advertisers`
  ADD CONSTRAINT `advertisers_ibfk_1` FOREIGN KEY (`advertiser_id`) 
      REFERENCES `jobs` (`advertiser_id`);

...実際には、本来あるべき姿とは正反対です。つまり、広告主の前にジョブテーブルにレコードがなければならないということです。だからあなたは使う必要があります:

ALTER TABLE `jobs`
  ADD CONSTRAINT `advertisers_ibfk_1` FOREIGN KEY (`advertiser_id`) 
      REFERENCES `advertisers` (`advertiser_id`);

外部キーの関係を修正すると、削除ステートメントが機能します。


3
最初の行:「それを参照する」ではなく「それを参照する」と考えるべきではありませんか?それとも、参照用語がどのように機能すると想定されているのかを誤解していますか?
アブラハムフィリップ

6
@AbrahamPhilip私も同じことを考えていました。広告主は仕事を参照します。
キーヤー

270

簡単な方法は、外部キーチェックを無効にすることです。変更を加えてから、外部キーチェックを再度有効にします。

SET FOREIGN_KEY_CHECKS=0; -- to disable them
SET FOREIGN_KEY_CHECKS=1; -- to re-enable them

171
これは問題の解決策ではなく、望ましくない可能性のある汚い回避策です。
マッドフレンド

20
私の場合:大きなSQLファイルを実行しただけで、最後のステートメントの1つが失敗したため、すべてのテーブルを削除し、構文エラーを修正して、再実行し、これをまさに探していたものにしました。
ekerner 2014年

1
これを行う場合は、すべての制約を削除しないでください。
Sablefoste

1
以下のような何かをするときに便利です:REPLACE INTO tab_with_constraint ...
MaciekŁoziński

5
この回答を賛成する唯一の理由は、自分が書いているコードを理解せずに、コードが怒鳴るのをやめてスパゲッティをより深く作り出したい場合です。そもそも外部キーを持つ理由は、参照整合性を強化するためです。コードをシャットダウンするために無効にする必要がある場合は、無効にするのではなく、外部キーを再考する必要があります。
キチヌス

38

現在の(欠陥がある可能性がある)設計では、参照する求人テーブルの行を削除するに、広告主テーブルから行を削除する必要があります。

または、親テーブルでの削除によって子テーブルの行が自動的に削除されるように外部キーを設定することもできます。これは、カスケード削除と呼ばれます。次のようになります。

ALTER TABLE `advertisers`
ADD CONSTRAINT `advertisers_ibfk_1`
FOREIGN KEY (`advertiser_id`) REFERENCES `jobs` (`advertiser_id`)
ON DELETE CASCADE;

そうは言っても、他の人がすでに指摘したように、advertisersテーブルには実際に主キーが含まれており、jobsテーブルには外部キーが含まれているため、外部キーは逆に移動する必要があるように感じます。私はそれを次のように書き直します:

ALTER TABLE `jobs`
ADD FOREIGN KEY (`advertiser_id`) REFERENCES `advertisers` (`advertiser_id`);

また、カスケード削除は必要ありません。


18

テーブルを削除する場合は、次のクエリを1つのステップで実行する必要があります

SET FOREIGN_KEY_CHECKS = 0; DROP TABLE table_name;


13

@Alino Manziが述べた解決策を試しましたが、wpdbを使用したWordPress関連のテーブルではうまくいきませんでした。

それから私は以下のようにコードを変更し、それはうまくいきました

SET FOREIGN_KEY_CHECKS=OFF; //disabling foreign key

//run the queries which are giving foreign key errors

SET FOREIGN_KEY_CHECKS=ON; // enabling foreign key

6

あなたの外部キーは後方にあると思います。試してください:

ALTER TABLE 'jobs'
ADD CONSTRAINT `advertisers_ibfk_1` FOREIGN KEY (`advertiser_id`) REFERENCES `advertisers` (`advertiser_id`)

5

同じadvertiser_idを持つジョブが複数ある場合、外部キーは次のようになります。

ALTER TABLE `jobs`
ADD CONSTRAINT `advertisers_ibfk_1` 
FOREIGN KEY (`advertiser_id`) 
REFERENCES `advertisers` (`advertiser_id`);

それ以外の場合(ケースの逆の場合)、ジョブの行が削除された場合に広告主の行を自動的に削除する場合は、外部キーの末尾に「ON DELETE CASCADE」オプションを追加します。

ALTER TABLE `advertisers`
ADD CONSTRAINT `advertisers_ibfk_1` 
FOREIGN KEY (`advertiser_id`) 
REFERENCES `jobs` (`advertiser_id`)
ON DELETE CASCADE;

外部キー制約を確認する



2

データベースまたはテーブルを作成するとき

その行をスクリプトの作成データベースまたはテーブルに追加する必要があります

SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=1;

次に、テーブルからレコードを削除しますか?それからあなたは

SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=1;
DELETE FROM `jobs` WHERE `job_id` =1 LIMIT 1

幸運を!


2

私が使用してきたこの代替案はどうですか:外部キーをNULLにしてからON DELETE SET NULLを選択してください。

個人的には、 " ON UPDATE CASCADE "と " ON DELETE SET NULL "の両方を使用して不要な複雑化を避けることを好みますが、セットアップでは別のアプローチが必要になる場合があります。また、外部キー値をNULLにすると、そこで何が起こったのか正確にわからないため、後で複雑になる可能性があります。したがって、この変更は、アプリケーションコードの動作に密接に関連しているはずです。

お役に立てれば。


2

laravelの移行でこの問題が発生しました。down
()メソッドでのドロップテーブルの順序も重要です

Schema::dropIfExists('groups');
Schema::dropIfExists('contact');

機能しない可能性がありますが、順序を変更すると機能します。

Schema::dropIfExists('contact');
Schema::dropIfExists('groups');

1

クライアントをできるだけ早くサポートする必要があり、アクセスできない場合

FOREIGN_KEY_CHECKS

データの整合性を無効にできるように:

1)外部キーを削除する

ALTER TABLE `advertisers` 
DROP FOREIGN KEY `advertisers_ibfk_1`;

2)SQLまたはAPIによる削除操作をアクティブ化します

3)外部キーをスキーマに追加します

ALTER TABLE `advertisers`
  ADD CONSTRAINT `advertisers_ibfk_1` FOREIGN KEY (`advertiser_id`) REFERENCES `jobs` (`advertiser_id`);

ただし、これはホットフィックスであるため、手動でデータの整合性を維持するために後で必要になるというアプローチの主な欠点があるため、ユーザー自身の責任で行ってください。


0

ジョブを削除する前に、参照された行を削除するトリガーを作成できます。

    DELIMITER $$
    CREATE TRIGGER before_jobs_delete 
        BEFORE DELETE ON jobs
        FOR EACH ROW 
    BEGIN
        delete from advertisers where advertiser_id=OLD.advertiser_id;
    END$$
    DELIMITER ;

0

このエラーの主な問題Error Code: 1451. Cannot delete or update a parent row: a foreign key constraint failsは、どのテーブルに FKエラーが含まれているかがわからないため、競合を解決するのが難しいことです。

MySQLなどを使用している場合は、データベースのER図を作成できることがわかりました。その後、エラーの原因となっている競合を確認して安全に削除できます。

  1. MySQLワークベンチを使用する
  2. データベース->リバースエンジニアリングをクリックします
  3. 正しいを選択してください connection
  4. 最後まで続いて、選択することを忘れないでくださいdatabasetablesその必要性を検討します
  5. これでERダイアグラムが作成され、どのテーブルがFK競合を持っているかを確認できます

0

基本的に、これらのタイプのエラーの背後にある理由は、主キー(ルートテーブル)を持つタプルを削除しようとしていることと、その主キーが子テーブルで外部キーとして使用されていることです。このシナリオでは、親テーブルデータを削除するために、(外部キーが使用されている)子テーブルデータを削除する必要があります。ありがとう


0

これは私にも起こり、他のテーブルからの依存関係と参照が原因で、エントリを削除できませんでした。私が行ったのは、テーブルに(ブール型の)列を削除することです。そのフィールドの値は、アイテムが削除対象としてマークされているかどうかを示しています。削除対象としてマークされている場合は、フェッチ/使用しないでください。それ以外の場合は使用してください。


-1

たぶんあなたはON DELETE CASCADEを試すべきです


34
問題を理解せずにカスケード削除(データを破壊する)を盲目的に追加することは、実行できる最悪のことです。
トムH
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.