MySQLがerrnoを与える外部キーを持つテーブルを作成する:150


98

他の2つのテーブルの主キーを参照する2つの外部キーを持つMySQLでテーブルを作成しようとしていますが、errno:150エラーが発生し、テーブルが作成されません。

3つのテーブルすべてのSQLは次のとおりです。

CREATE TABLE role_groups (
  `role_group_id` int(11) NOT NULL `AUTO_INCREMENT`,
  `name` varchar(20),
  `description` varchar(200),
  PRIMARY KEY (`role_group_id`)
) ENGINE=InnoDB;

CREATE TABLE IF NOT EXISTS `roles` (
  `role_id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(50),
  `description` varchar(200),
  PRIMARY KEY (`role_id`)
) ENGINE=InnoDB;

create table role_map (
  `role_map_id` int not null `auto_increment`,
  `role_id` int not null,
  `role_group_id` int not null,
  primary key(`role_map_id`),
  foreign key(`role_id`) references roles(`role_id`),
  foreign key(`role_group_id`) references role_groups(`role_group_id`)
) engine=InnoDB;

どんな助けでも大歓迎です。


1
エラー出力を投稿して、(3つのうち)エラーを引き起こしているコマンドを教えてください。
デイブ

4
周りのバックティックとは何auto_incrementですか?それは無効です。Auto_incrementはキーワードであり、識別子ではありません。
ビルカーウィン

回答:


238

と同じ問題がありましたALTER TABLE ADD FOREIGN KEY

1時間後、エラー150が発生しないようにするには、これらの条件を満たす必要があることがわかりました。

  1. 参照する外部キーを定義する前に、親テーブルが存在している必要があります。テーブルは正しい順序で定義する必要があります。最初に親テーブル、次に子テーブルです。両方のテーブルが相互に参照している場合は、FK制約なしで1つのテーブルを作成し、2番目のテーブルを作成してから、最初のテーブルにFK制約を追加する必要がありますALTER TABLE

  2. 2つのテーブルはどちらも外部キー制約をサポートする必要がありENGINE=InnoDBます。他のストレージエンジンは外部キー定義を暗黙的に無視するため、エラーや警告は返されませんが、FK制約は保存されません。

  3. 親テーブルで参照される列は、キーの左端の列でなければなりません。ベスト親のキーがある場合PRIMARY KEY、またはUNIQUE KEY

  4. FK定義は、PK定義と同じ順序でPK列を参照する必要があります。たとえば、FKのREFERENCES Parent(a,b,c)場合、親のPKを列に順番に定義しないでください(a,c,b)

  5. 親テーブルのPK列は、子テーブルのFK列と同じデータ型である必要があります。たとえば、親テーブルのPK列がの場合、UNSIGNED必ずUNSIGNED子テーブルフィールドの対応する列に定義してください。

    例外:文字列の長さが異なる場合があります。たとえば、VARCHAR(10)参照することVARCHAR(20)も、その逆も可能です。

  6. 文字列タイプのFK列には、対応するPK列と同じ文字セットと照合順序が必要です。

  7. すでに子テーブルにデータがある場合、FK列のすべての値は、親テーブルのPK列の値と一致する必要があります。次のようなクエリでこれを確認します。

    SELECT COUNT(*) FROM Child LEFT OUTER JOIN Parent ON Child.FK = Parent.PK 
    WHERE Parent.PK IS NULL;

    これは、ゼロ(0)の一致しない値を返す必要があります。明らかに、このクエリは一般的な例です。テーブル名と列名を置き換える必要があります。

  8. 親テーブルも子テーブルもテーブルにすることはできませんTEMPORARY

  9. 親テーブルも子テーブルもテーブルにすることはできませんPARTITIONED

  10. オプションを使用してFKを宣言する場合ON DELETE SET NULL、FK列はNULL可能でなければなりません。

  11. 外部キーの制約名を宣言する場合、制約名は、制約が定義されているテーブルだけでなく、スキーマ全体で一意である必要があります。2つのテーブルに同じ名前の独自の制約がない場合があります。

  12. 新しいFKを作成しようとしている同じフィールドを指している他のテーブルに他のFKがあり、それらが不正な形式(つまり、照合順序が異なる)である場合は、最初に一貫性を持たせる必要があります。これはSET FOREIGN_KEY_CHECKS = 0;、誤って定義された一貫性のない関係で使用された過去の変更の結果である可能性があります。これらの問題のFKを特定する方法については、以下の@andrewdotnの回答を参照してください。

お役に立てれば。


4
もう1つ追加する価値があります。親テーブルのPKが複数のフィールドである場合、FKのフィールドの順序は、PKの順序と同じでなければなりません
Kip

26
これにはint(11) unsigned NOT NULLvsのようなものが含まれますint(11) NOT NULL
Glen Solsberry、2013年

4
ALTER TABLE table_name ENGINE = InnoDB;
TolMera 2013

12
テーブルがENGINE = MyISAMと定義されている場合、外部キーの宣言を無視するため、errno 150は生成されません。自動車のエンジンのトラブルを回避する最善の方法は、ボートを運転することです。:-)
Bill Karwin 2013年

2
また、CONSTRAINTのON DELETEルールがSET NULL外部キーが実際にNULLになる可能性があることを確認してください!私はこの答えを何度も繰り返し読んで、テーブルが条件を満たしていることを確認しましたが、それでもエラー150が発生しました。その後、FKがNOT NULLフィールドであり、ルールを適用できないことを確認しました。
マーティンジョイナー2015年

62

MySQLの一般的な「errno 150」メッセージは、「外部キー制約が正しく形成されなかったことを意味します。」このページを読んでいるかどうかはご存じでしょうが、一般的な「errno:150」エラーメッセージは役に立ちません。しかしながら:

実際のエラーメッセージを取得するには、実行してから出力をSHOW ENGINE INNODB STATUS;探しLATEST FOREIGN KEY ERRORます。

たとえば、次の外部キー制約を作成しようとします。

CREATE TABLE t1
(id INTEGER);

CREATE TABLE t2
(t1_id INTEGER,
 CONSTRAINT FOREIGN KEY (t1_id) REFERENCES t1 (id));

エラーで失敗しますCan't create table 'test.t2' (errno: 150)。それは、それが外部キーの問題であることを除いて、誰にも有用なことを何も伝えていません。しかし、実行するSHOW ENGINE INNODB STATUS;と次のようになります。

------------------------
LATEST FOREIGN KEY ERROR
------------------------
130811 23:36:38 Error in foreign key constraint of table test/t2:
FOREIGN KEY (t1_id) REFERENCES t1 (id)):
Cannot find an index in the referenced table where the
referenced columns appear as the first columns, or column types
in the table and the referenced table do not match for constraint.

問題は、インデックスが見つからないということです。SHOW INDEX FROM t1は、tableのインデックスがまったくないことを示していますt1。たとえば、に主キーを定義することで修正しt1、外部キー制約が正常に作成されます。


4
SHOW ENGINE INNODB STATUS1時間近く診断しようとしていた問題をすぐに特定できるようになりました。ありがとう。
jatrim 2014

私の場合、これは、私がポイントしようとしていた同じフィールドをFKした完全に異なるテーブルが一貫していないため、新しいテーブルを保存しないことを示しています...これSET FOREIGN_KEY_CHECKS = 0;が不正なインポート/変更中に使用されたと想定いつか別の時に。大きな助け、ありがとう。
oucil

25

制約とリンクしようとしている2つのフィールドのプロパティが完全に同じであることを確認してください。

多くの場合、ID列の「署名されていない」プロパティが目を引きます。

ALTER TABLE `dbname`.`tablename` CHANGE `fieldname` `fieldname` int(10) UNSIGNED NULL;

私の経験では、メインテーブルでMySQLのSHOW CREATE TABLEを使用して、メインインデックス列に対して設定されているフラグを正確に確認し、それらを外部キー列にコピーすることは価値があります。「unsigned」のように、はっきりしないものがあるかもしれません。
Ambulare 2014

10

このスクリプトを実行すると、データベースの現在の状態はどうなりますか?完全に空ですか?データベースを最初から作成すると、SQLは問題なく動作しますが、通常、errno 150は、外部キーの一部であるテーブルの削除と再作成に関係しています。100%フレッシュで新しいデータベースで作業していないような気がします。

SQLファイルを「ソース」するときにエラーが発生する場合は、「ソース」コマンドの直後にMySQLプロンプトから「SHOW ENGINE INNODB STATUS」コマンドを実行して、より詳細なエラー情報を表示できるはずです。

手動で入力することもできます。

削除されたテーブルを再作成する場合、そのテーブルを参照する外部キー制約に準拠する定義が必要です。前述のように、適切な列名と型があり、参照されるキーにインデックスが必要です。これらが満たされない場合、MySQLはエラー番号1005を返し、エラーメッセージのエラー150を参照します。MySQLがCREATE TABLEステートメントからエラー番号1005を報告し、エラーメッセージがエラー150を参照している場合、外部キー制約が正しく形成されていなかったため、テーブルの作成は失敗しました。

MySQL 5.1リファレンスマニュアル


5

同じ問題でこのスレッドを見ている人のために:

このようなエラーが発生する理由はたくさんあります。MySQLの外部キーエラーの原因と解決策のかなり完全なリスト(ここで説明したものを含む)については、次のリンクを確認してください。

MySQL外部キーエラーとErrno 150


4

Googleを介してこのSOエントリを見つけた他のユーザー向け:「NOT NULL」として定義された外部キー(であるべき)列に対してSET NULLアクションを実行しないようにしてください。私がCHECK ENGINE INNODB STATUSを実行することを思い出すまで、それは大きなフラストレーションを引き起こしました。


3

間違いなくそうではありませんが、この間違いはかなり一般的で自明ではありません。のターゲットはFOREIGN KEYできませんPRIMARY KEY。私にとって有用になる答えは次のとおりです。

FOREIGN KEYは、常に他のテーブルのPRIMARY KEY trueフィールドを指す必要があります。

CREATE TABLE users(
   id INT AUTO_INCREMENT PRIMARY KEY,
   username VARCHAR(40));

CREATE TABLE userroles(
   id INT AUTO_INCREMENT PRIMARY KEY,
   user_id INT NOT NULL,
   FOREIGN KEY(user_id) REFERENCES users(id));

3

@andrewdotnで指摘されているように、最善の方法は詳細なエラーを表示することです(SHOW ENGINE INNODB STATUS;、エラーコードだけでなく)を表示することです。

理由の1つは、同じ名前のインデックスが既に存在しているか、別のテーブルにある可能性があります。実際には、このような衝突を避けるために、インデックス名の前にテーブル名を付けることをお勧めします。たとえば、idx_userId使用する代わりにidx_userActionMapping_userId


3

最初にそれを確認してください

  1. InnoDBテーブルを使用しています。
  2. FOREIGN KEYのフィールドには、ソースフィールドと同じタイプと長さ(!)があります。

同じ問題が発生したので修正しました。私は、1つのフィールドに符号なしINTを、他のフィールドには整数のみを使用していました。


2

役立つヒント、クエリをSHOW WARNINGS;試行した後に使用CREATEすると、エラーと詳細な警告が表示されます。

    ---------------------------------------------------------------------------------------------------------+
| Level   | Code | Message                                                                                                                                                                                                                                 |
+---------+------+--------------------------------------------------------------------------                          --------------------------------------------------------------------------------------------                          ---------------+
| Warning |  150 | Create table 'fakeDatabase/exampleTable' with foreign key constraint failed. There is no index in the referenced table where the referenced columns appear as the first columns.
|
| Error   | 1005 | Can't create table 'exampleTable' (errno:150)                                                                                                                                                                           |
+---------+------+--------------------------------------------------------------------------                          --------------------------------------------------------------------------------------------                          ---------------+

この場合、テーブルを再作成する時間です!


1

これは通常、既存のデータベースにファイルをソースしようとしたときに発生します。最初にすべてのテーブル(またはDB自体)を削除します。そしてSET foreign_key_checks = 0;、最初とSET foreign_key_checks = 1;最後にソースファイルを置きます。


1

これが失敗する別の理由を見つけました...大文字と小文字を区別するテーブル名。

このテーブル定義について

CREATE TABLE user (
  userId int PRIMARY KEY AUTO_INCREMENT,
  username varchar(30) NOT NULL
) ENGINE=InnoDB;

このテーブル定義は機能します

CREATE TABLE product (
  id int PRIMARY KEY AUTO_INCREMENT,
  userId int,
  FOREIGN KEY fkProductUser1(userId) REFERENCES **u**ser(userId)
) ENGINE=InnoDB;

これは失敗しますが

CREATE TABLE product (
  id int PRIMARY KEY AUTO_INCREMENT,
  userId int,
  FOREIGN KEY fkProductUser1(userId) REFERENCES User(userId)
) ENGINE=InnoDB;

Windowsでは機能し、Unixでは機能しなかったという事実を理解するには、数時間かかりました。それが他の誰かを助けることを願っています。


1

Mac OS用のMySQL Workbench 6.3。

問題:DBダイアグラムでフォワードエンジニアリングを実行しようとすると、テーブルXでerrno 150、21のうち20が成功、1が失敗。テーブルXのFKが削除された場合、エラーは以前は失敗していなかった別のテーブルに移動しました。

すべてのテーブルエンジンをmyISAMに変更し、正常に動作しました。

ここに画像の説明を入力してください


0

また、間違ったデータベースで誤って操作していないことを確認する価値もあります。このエラーは、外部テーブルが存在しない場合に発生します。MySQLはなぜそんなに不可解である必要があるのですか?


0

外部キーが親で一意としてリストされていないことを確認してください。私はこれと同じ問題を抱えていましたが、それを一意でないものとして区別することで解決しました。


0

私の場合、外部キーフィールドであるフィールドの名前が長すぎるという事実が原因でした。foreign key (some_other_table_with_long_name_id)。sthを短くしてみてください。その場合、エラーメッセージは少し誤解を招きます。

また、@ Jonが前述したように、フィールド定義は同じである必要があります(unsignedサブタイプに注意)。


0

(サイドノートがコメントには大きすぎます)

AUTO_INCREMENTマッピングテーブルにIDは必要ありません。それを取り除く。

PRIMARY KEY(role_id, role_group_id)(いずれかの順序で)に変更します。これにより、アクセスが速くなります。

おそらく両方の方向をマッピングしたいのでINDEX、これらの2つの列を逆の順序で追加します。(作成する必要はありませんUNIQUE。)

その他のヒント:http : //mysql.rjweb.org/doc.php/index_cookbook_mysql#speeding_up_wp_postmeta



0

テーブルを作成する前に以下の行を実行します:SET FOREIGN_KEY_CHECKS = 0;

FOREIGN_KEY_CHECKSオプションは、InnoDBテーブルの外部キー制約をチェックするかどうかを指定します。

-外部キー制約をチェックすることを指定します(これがデフォルトです)

SET FOREIGN_KEY_CHECKS = 1;

 

-外部キー制約をチェックしません

SET FOREIGN_KEY_CHECKS = 0;

いつ使用するか:一時的に参照制約を無効にする(FOREIGN_KEY_CHECKSを0に設定する)は、テーブルを再作成し、親子の順序でデータをロードする必要がある場合に役立ちます。


-1

同じ問題が発生しましたが、親テーブルがないことを確認しました。したがって、私は子の移行の前に親の移行を編集するだけです。早くやれよ。


1
これは、代わりに答えのコメントされている必要があります
hannadレーマン
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.