MySQLで2つの外部キーを持つテーブルを作成しようとしていますが、これらは他の2つのテーブルのプライマリキーを参照しますが、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;
どんな助けも大歓迎です。
ALTER TABLE ADD FOREIGN KEY
でも同じ問題が発生しました。
1時間後、エラー150が発生しないように、これらの条件を満たしている必要があることがわかりました。
親テーブルは、それを参照する外部キーを定義する前に存在している必要があります。テーブルを正しい順序で定義する必要があります。最初に親テーブル、次に子テーブルを定義します。両方のテーブルが相互に参照する場合、FK制約なしで1つのテーブルを作成し、2番目のテーブルを作成してから、ALTER TABLE
でFK制約を最初のテーブルに追加する必要があります。
2つのテーブルは両方とも外部キー制約、つまりENGINE=InnoDB
をサポートする必要があります。他のストレージエンジンは外部キーの定義を黙って無視するため、エラーや警告は返されませんが、FK制約は保存されません。
親テーブルの参照列は、キーの左端の列でなければなりません。親のキーがPRIMARY KEY
またはUNIQUE KEY
である場合に最適です。
FK定義は、PK定義と同じ順序でPK列を参照する必要があります。たとえば、FK REFERENCES Parent(a,b,c)
の場合、親のPKは(a,c,b)
の順序で列に定義してはいけません。
親テーブルのPK列は、子テーブルのFK列と同じデータ型である必要があります。たとえば、親テーブルのPK列がUNSIGNED
である場合、子テーブルフィールドの対応する列にUNSIGNED
を定義してください。
例外:文字列の長さが異なる場合があります。たとえば、VARCHAR(10)
はVARCHAR(20)
を参照できます。
文字列型のFK列には、対応するPK列と同じ文字セットと照合順序が必要です。
子テーブルに既にデータがある場合、FK列のすべての値は、親テーブルのPK列の値と一致する必要があります。次のようなクエリでこれを確認します。
SELECT COUNT(*) FROM Child LEFT OUTER JOIN Parent ON Child.FK = Parent.PK
WHERE Parent.PK IS NULL;
これはゼロ(0)の不一致値を返す必要があります。明らかに、このクエリは一般的な例です。テーブル名と列名を置き換える必要があります。
親テーブルも子テーブルもTEMPORARY
テーブルにすることはできません。
親テーブルも子テーブルもPARTITIONED
テーブルにすることはできません。
ON DELETE SET NULL
オプションを使用してFKを宣言する場合、FK列はNULL可能でなければなりません。
外部キーの制約名を宣言する場合、制約名は、制約が定義されているテーブルだけでなく、スキーマ全体で一意でなければなりません。 2つのテーブルに同じ名前の独自の制約がない場合があります。
新しいFKを作成しようとしている同じフィールドを指している他のテーブルに他のFKがあり、それらが不正な形式(つまり、異なる照合)である場合、最初に一貫性を保つ必要があります。これは、SET FOREIGN_KEY_CHECKS = 0;
が誤って定義された一貫性のない関係で使用された過去の変更の結果である可能性があります。これらの問題のあるFKを識別する方法については、以下の@andrewdotnの回答を参照してください。
お役に立てれば。
MySQLの一般的な「errno 150」メッセージ「 外部キー制約が正しく形成されなかったことを意味する 」。このページを読んでいるかどうかはご存知でしょうが、一般的な「errno:150」エラー役に立たない。しかしながら:
SHOW ENGINE INNODB STATUS;
を実行し、出力でLATEST FOREIGN KEY ERROR
を検索すると、actualエラーメッセージを取得できます。
たとえば、これは外部キー制約を作成しようとします:
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
は、テーブルt1
のインデックスがまったくないことを示しています。たとえば、t1
で主キーを定義することで修正すると、外部キー制約が正常に作成されます。
制約とリンクしようとしている2つのフィールドのプロパティが完全に同じであることを確認してください。
多くの場合、ID列の「unsigned」プロパティがあなたを捕まえます。
ALTER TABLE `dbname`.`tablename` CHANGE `fieldname` `fieldname` int(10) UNSIGNED NULL;
このスクリプトを実行したときのデータベースの現在の状態は何ですか?完全に空ですか?データベースをゼロから作成する場合、SQLは正常に動作しますが、errno 150は通常、外部キーの一部であるテーブルの削除と再作成に関係しています。 100%新鮮な新しいデータベースで作業していない気がします。
SQLファイルを「ソース」するときにエラーが発生する場合は、「ソース」コマンドの直後にMySQLプロンプトから「SHOW ENGINE INNODB STATUS」コマンドを実行して、より詳細なエラー情報を表示できるはずです。
手動入力も確認してください。
削除されたテーブルを再作成する場合、それを参照する外部キー制約に準拠する定義が必要です。前述のように、適切な列名と型が必要であり、参照されるキーにインデックスが必要です。これらが満たされない場合、MySQLはエラー番号1005を返し、エラーメッセージでエラー150を参照します。 MySQLがCREATE TABLEステートメントからエラー番号1005を報告し、エラーメッセージがエラー150を指している場合、外部キー制約が正しく形成されていないため、テーブルの作成に失敗しました。
同じ問題でこのスレッドを見ている人のために:
このようなエラーが発生する理由はたくさんあります。 MySQLの外部キーエラー(ここで説明したものを含む)の原因と解決策のかなり完全なリストについては、次のリンクを参照してください。
Google経由でこのSOエントリを見つける他の人:「NOT NULL」として定義された外部キー(予定)列に対してSET NULLアクションを実行しようとしていないことを確認してください。 ENGINE INNODB STATUSを確認することを思い出すまで、それは大きな不満を引き起こしました。
最初にそれを確認してください
私は同じトラブルを抱えていたので修正しました。 1つのフィールドには符号なしINTがあり、他のフィールドには整数だけがありました。
@andrewdotnが指摘したように、最善の方法は、エラーコードだけでなく詳細なエラー(SHOW ENGINE INNODB STATUS;
)を確認することです。
理由の1つは、同じ名前のインデックスがすでに存在し、別のテーブルにある可能性があることです。慣例として、このような衝突を避けるために、インデックス名の前にテーブル名をプレフィックスすることをお勧めします。例えばidx_userId
の代わりにidx_userActionMapping_userId
を使用します。
確かにそうではありませんが、この間違いはかなり一般的で明白ではありませんでした。 FOREIGN KEY
のターゲットはPRIMARY KEY
ではありません。私にとって役立つ答えは次のとおりです。
外部キーは常に他のテーブルのプライマリキーの真のフィールドを指している必要があります。
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));
役立つヒント、CREATE
クエリを試行した後にSHOW WARNINGS;
を使用すると、エラーと詳細な警告が表示されます。
---------------------------------------------------------------------------------------------------------+
| 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) |
+---------+------+-------------------------------------------------------------------------- -------------------------------------------------------------------------------------------- ---------------+
この場合、テーブルを再作成する時間です!
これは通常、既存のデータベースにファイルをソースしようとすると発生します。最初にすべてのテーブル(またはDB自体)をドロップします。そして、SET foreign_key_checks = 0;
を先頭に、SET foreign_key_checks = 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で失敗したという事実を理解するのに数時間かかりました。それが誰かを助けることを願っています。
外部キーが親で一意としてリストされていないことを確認してください。私はこれと同じ問題を抱えていたので、それを一意でないものとして区別することで解決しました。
また、誤って誤ったデータベースを操作していないことを確認する価値があります。このエラーは、外部テーブルが存在しない場合に発生します。なぜMySQLはそんなに不可解である必要があるのですか?
外部キー制約がvarchar
タイプに基づいている場合、 marv-el
によって提供されるリスト に加えて、target列には一意の制約
(サイドノートはコメントするには大きすぎる)
マッピングテーブルにAUTO_INCREMENT
idは必要ありません。それを取り除きます。
PRIMARY KEY
を(role_id, role_group_id)
に変更します(どちらの順序でも)。これにより、アクセスが高速になります。
おそらく両方の方向をマップする必要があるため、これらの2つの列を反対の順序でINDEX
も追加します。 (それをUNIQUE
にする必要はありません。)
その他のヒント: http://mysql.rjweb.org/doc.php/index_cookbook_mysql#speeding_up_wp_postmeta
私の場合、外部キーフィールドであるフィールドの名前が長すぎたためです。 foreign key (some_other_table_with_long_name_id)
。 sthを短くしてみてください。その場合、エラーメッセージは少し誤解を招く可能性があります。
また、@ Jonが前述したように、フィールド定義は同じである必要があります(unsigned
サブタイプに注意してください)。