Ik had hetzelfde probleem met ALTER TABLE ADD FOREIGN KEY
.
Na een uur ontdekte ik dat aan deze voorwaarden moet worden voldaan om fout 150 niet te krijgen:
-
De bovenliggende tabel moet bestaan voordat u een refererende sleutel definieert om ernaar te verwijzen. U moet de tabellen in de juiste volgorde definiëren:eerst de bovenliggende tabel, dan de onderliggende tabel. Als beide tabellen naar elkaar verwijzen, moet u één tabel maken zonder FK-beperkingen, vervolgens de tweede tabel maken en vervolgens de FK-beperking aan de eerste tabel toevoegen met
ALTER TABLE
. -
De twee tabellen moeten beide externe-sleutelbeperkingen ondersteunen, d.w.z.
ENGINE=InnoDB
. Andere opslag-engines negeren de definities van buitenlandse sleutels stilletjes, dus ze geven geen fout of waarschuwing terug, maar de FK-beperking wordt niet opgeslagen. -
De kolommen waarnaar in de bovenliggende tabel wordt verwezen, moeten de meest linkse kolommen van een sleutel zijn. Het beste als de sleutel in de bovenliggende sleutel
PRIMARY KEY
is ofUNIQUE KEY
. -
De FK-definitie moet verwijzen naar de PK-kolom(men) in dezelfde volgorde als de PK-definitie. Als de FK
REFERENCES Parent(a,b,c)
dan mag de PK van de ouder niet op volgorde van kolommen worden gedefinieerd(a,c,b)
. -
De PK-kolom(men) in de Bovenliggende tabel moeten hetzelfde gegevenstype hebben als de FK-kolom(men) in de Onderliggende tabel. Als een PK-kolom in de bovenliggende tabel bijvoorbeeld
UNSIGNED
. is , zorg ervoor dat uUNSIGNED
definieert voor de corresponderende kolom in het veld Onderliggende tabel.Uitzondering:de lengte van de snaren kan verschillen. Bijvoorbeeld
VARCHAR(10)
kan verwijzen naarVARCHAR(20)
of omgekeerd. -
Alle FK-kolom(men) van het tekenreekstype moeten dezelfde tekenset en sortering hebben als de corresponderende PK-kolom(men).
-
Als er al gegevens in de onderliggende tabel staan, moet elke waarde in de FK-kolom(men) overeenkomen met een waarde in de PK-kolom(men) van de bovenliggende tabel. Controleer dit met een vraag als:
SELECT COUNT(*) FROM Child LEFT OUTER JOIN Parent ON Child.FK = Parent.PK WHERE Parent.PK IS NULL;
Dit moet nul (0) niet-overeenkomende waarden retourneren. Het is duidelijk dat deze query een generiek voorbeeld is; u moet uw tabelnamen en kolomnamen vervangen.
-
Noch de bovenliggende tabel, noch de onderliggende tabel kan een
TEMPORARY
zijn tafel. -
Noch de bovenliggende tabel, noch de onderliggende tabel kan een
PARTITIONED
. zijn tafel. -
Als u een FK declareert met de
ON DELETE SET NULL
optie, dan moeten de FK-kolom(men) nullable zijn. -
Als u een beperkingsnaam voor een externe sleutel declareert, moet de beperkingsnaam uniek zijn in het hele schema, niet alleen in de tabel waarin de beperking is gedefinieerd. Twee tabellen hebben mogelijk geen eigen beperking met dezelfde naam.
-
Als er andere FK's in andere tabellen zijn die naar hetzelfde veld wijzen waarvoor u de nieuwe FK probeert te maken, en deze zijn niet correct gevormd (d.w.z. een andere sortering), moeten ze eerst consistent worden gemaakt. Dit kan het gevolg zijn van eerdere wijzigingen waarbij
SET FOREIGN_KEY_CHECKS = 0;
werd gebruikt met een per abuis gedefinieerde inconsistente relatie. Zie het antwoord van @andrewdotn hieronder voor instructies om deze probleem-FK's te identificeren.
Ik hoop dat dit helpt.