外部キー列は、主キーの左端のプレフィックスまたは親テーブルの一意キーを含む列を参照する必要があります。
つまり、次の例はInnoDBで機能します。
CREATE TABLE Foo ( a INT, b INT, c INT, PRIMARY KEY (a,b,c) );
CREATE TABLE Bar ( x INT, y INT );
ALTER TABLE Bar ADD FOREIGN KEY (x,y) REFERENCES Foo(b,c); -- WRONG
ALTER TABLE Bar ADD FOREIGN KEY (x,y) REFERENCES Foo(a,c); -- WRONG
ALTER TABLE Bar ADD FOREIGN KEY (x,y) REFERENCES Foo(a,b); -- RIGHT
ALTER TABLE Bar ADD FOREIGN KEY (x) REFERENCES Foo(b); -- WRONG
ALTER TABLE Bar ADD FOREIGN KEY (x) REFERENCES Foo(a); -- RIGHT
(x)参照Foo(b)と同等の処理を行おうとしているため、エラーが発生しました。
列codmenuitemは、親の主キーの3つの列の2番目です。
smenuitememp.codemenuitem
があれば機能します smenuitem.codmodulo
を参照することになっていました 、その列は親テーブルの主キーの左端の列であるためです。
フォローアップの質問について:
外部キーの動作方法に注意してください。子テーブルの行を挿入または更新するたびに、親テーブルの行を検索して、参照されている列に値が存在することを確認する必要があります。列にインデックスが付けられていない場合、このルックアップを実現するにはテーブルスキャンを実行する必要があり、親テーブルが大きくなると仮定すると、これは非常にコストがかかります。
複数列のインデックスの中央の列に基づいて行を検索しようとすると、インデックスは役に立ちません。類推すると、特定のミドルネームを持つすべての人を電話帳で検索するようなものです。
標準のANSISQLでは、参照される列がPRIMARYKEYまたはUNIQUEKEYの一部である必要があり、外部キー列が allと一致する必要があります。 親の主制約または一意制約の列。
しかし、InnoDBはより寛容です。ルックアップを効率的に行えるように、親テーブルの参照列にインデックスを付ける必要があります。および 参照される列がインデックスの左端にあること。ただし、一意でないインデックスは問題ありません。外部キーがそれを参照することは許可されています。
これにより、親の複数の行を参照する子行のような奇妙なケースが発生する可能性がありますが、そのような異常を処理することが期待されます。
最後のポイントを強調する必要があると感じています。あなたは 親の一意にインデックス付けされていない列に外部キーを定義すると、異常なデータが取得されます。これにより、結合を行うときにクエリで行が複数回報告される可能性があります。 InnoDBのこの動作は使用しないでください。外部キーは、一意の親列にのみ定義する必要があります。