Sloupce cizího klíče musí odkazovat na sloupce obsahující předponu primárního klíče zcela vlevo nebo jedinečný klíč v nadřazené tabulce.
Jinými slovy, následující příklady fungují v 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
Došlo k chybě, protože se pokoušíte provést ekvivalent (x) odkazů Foo(b).
Váš sloupec codmenuitem je druhý ze tří sloupců v primárním klíči rodiče.
Fungovalo by to, kdyby smenuitememp.codemenuitem
odkazovali na smenuitem.codmodulo
, protože tento sloupec je sloupcem zcela vlevo v primárním klíči nadřazené tabulky.
K vaší doplňující otázce:
Mějte na paměti, jak fungují cizí klíče. Pokaždé, když vložíte nebo aktualizujete řádek v podřízené tabulce, je třeba vyhledat řádek v nadřazené tabulce, aby ověřil, že hodnota v odkazovaném sloupci existuje. Pokud sloupec není indexován, bude muset provést prohledávání tabulky, aby se dosáhlo tohoto vyhledávání, a to by bylo velmi drahé, za předpokladu, že vaše nadřazená tabulka roste.
Pokud se pokusíte vyhledat řádek podle prostředního sloupce vícesloupcového indexu, index vám nepomůže. Analogicky je to jako hledat v telefonním seznamu všechny lidi s určitým druhým jménem.
Standardní ANSI SQL vyžaduje, aby odkazovaný sloupec byl součástí PRIMARY KEY nebo UNIQUE KEY a vyžaduje, aby se sloupce cizího klíče shodovaly všem sloupce primárního nebo jedinečného omezení v nadřazeném objektu.
Ale InnoDB je tolerantnější. Stále vyžaduje, aby byl odkazovaný sloupec v nadřazené tabulce indexován, aby bylo vyhledávání efektivní, a že odkazované sloupce jsou v indexu úplně vlevo. Ale nejedinečný index je v pořádku; je povoleno, aby na něj odkazoval cizí klíč.
To může vést k podivným případům, jako je podřízený řádek, který odkazuje na více než jeden řádek v nadřazeném řádku, ale očekává se, že takové anomálie zvládnete.
Cítím potřebu zdůraznit poslední bod. budete získáte anomální data, pokud definujete cizí klíče pro nejedinečně indexované sloupce v nadřazeném prvku. To pravděpodobně způsobí, že vaše dotazy budou hlásit řádky vícekrát, když se připojíte. Toto chování InnoDB byste neměli používat; cizí klíče byste měli definovat pouze pro nadřazené sloupce, které jsou jedinečné.