Ho avuto lo stesso problema con ALTER TABLE ADD FOREIGN KEY
.
Dopo un'ora, ho scoperto che queste condizioni devono essere soddisfatte per non ricevere l'errore 150:
-
La tabella Parent deve esistere prima di definire una chiave esterna a cui fare riferimento. È necessario definire le tabelle nell'ordine corretto:prima la tabella padre, quindi la tabella figlio. Se entrambe le tabelle fanno riferimento l'una all'altra, devi creare una tabella senza vincoli FK, quindi creare la seconda tabella, quindi aggiungere il vincolo FK alla prima tabella con
ALTER TABLE
. -
Le due tabelle devono supportare entrambe i vincoli di chiave esterna, ovvero
ENGINE=InnoDB
. Altri motori di archiviazione ignorano silenziosamente le definizioni di chiavi esterne, quindi non restituiscono errori o avvisi, ma il vincolo FK non viene salvato. -
Le colonne di riferimento nella tabella padre devono essere le colonne più a sinistra di una chiave. Meglio se la chiave nella Parent è
PRIMARY KEY
oUNIQUE KEY
. -
La definizione FK deve fare riferimento alle colonne PK nello stesso ordine della definizione PK. Ad esempio, se l'FK
REFERENCES Parent(a,b,c)
quindi la PK del genitore non deve essere definita sulle colonne nell'ordine(a,c,b)
. -
Le colonne PK nella tabella padre devono essere dello stesso tipo di dati delle colonne FK nella tabella figlio. Ad esempio, se una colonna PK nella tabella padre è
UNSIGNED
, assicurati di definireUNSIGNED
per la colonna corrispondente nel campo Tabella figlio.Eccezione:la lunghezza delle stringhe potrebbe essere diversa. Ad esempio,
VARCHAR(10)
può fare riferimento aVARCHAR(20)
o viceversa. -
Qualsiasi colonna FK di tipo stringa deve avere lo stesso set di caratteri e regole di confronto delle colonne PK corrispondenti.
-
Se sono già presenti dati nella tabella Child, ogni valore nelle colonne FK deve corrispondere a un valore nelle colonne PK della tabella padre. Verifica questo con una query come:
SELECT COUNT(*) FROM Child LEFT OUTER JOIN Parent ON Child.FK = Parent.PK WHERE Parent.PK IS NULL;
Questo deve restituire zero (0) valori non corrispondenti. Ovviamente, questa query è un esempio generico; devi sostituire i nomi delle tabelle e delle colonne.
-
Né la tabella padre né la tabella figlio possono essere un
TEMPORARY
tabella. -
Né la tabella Parent né la tabella Child possono essere
PARTITIONED
tabella. -
Se dichiari un FK con il
ON DELETE SET NULL
opzione, le colonne FK devono essere nullable. -
Se si dichiara un nome di vincolo per una chiave esterna, il nome del vincolo deve essere univoco nell'intero schema, non solo nella tabella in cui è definito il vincolo. Due tabelle potrebbero non avere il proprio vincolo con lo stesso nome.
-
Se ci sono altri FK in altre tabelle che puntano allo stesso campo per il quale stai tentando di creare il nuovo FK e sono malformati (cioè con regole di confronto diverse), dovranno prima essere resi coerenti. Questo potrebbe essere il risultato di modifiche passate in cui
SET FOREIGN_KEY_CHECKS = 0;
è stato utilizzato con una relazione incoerente definita per errore. Vedi la risposta di @andrewdotn di seguito per istruzioni su come identificare questi FK problematici.
Spero che questo aiuti.