Errore Mysql 1452 - Impossibile aggiungere o aggiornare una riga figlio: un vincolo di chiave esterna non riesce


237

Sto avendo un problema un po 'strano. Sto cercando di aggiungere una chiave esterna a una tabella che fa riferimento a un'altra, ma per qualche motivo non riesce. Con la mia conoscenza limitata di MySQL, l'unica cosa che potrebbe essere sospetta è che ci sia una chiave esterna su una tabella diversa che fa riferimento a quella a cui sto cercando di fare riferimento.

Ho fatto una SHOW CREATE TABLEquery su entrambe le tabelle, sourcecodes_tagsè la tabella con la chiave esterna, sourcecodesè la tabella di riferimento.

CREATE TABLE `sourcecodes` (
 `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
 `user_id` int(11) unsigned NOT NULL,
 `language_id` int(11) unsigned NOT NULL,
 `category_id` int(11) unsigned NOT NULL,
 `title` varchar(40) CHARACTER SET utf8 NOT NULL,
 `description` text CHARACTER SET utf8 NOT NULL,
 `views` int(11) unsigned NOT NULL,
 `downloads` int(11) unsigned NOT NULL,
 `time_posted` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
 PRIMARY KEY (`id`),
 KEY `user_id` (`user_id`),
 KEY `language_id` (`language_id`),
 KEY `category_id` (`category_id`),
 CONSTRAINT `sourcecodes_ibfk_3` FOREIGN KEY (`language_id`) REFERENCES `languages` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
 CONSTRAINT `sourcecodes_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
 CONSTRAINT `sourcecodes_ibfk_2` FOREIGN KEY (`category_id`) REFERENCES `categories` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=latin1

CREATE TABLE `sourcecodes_tags` (
 `sourcecode_id` int(11) unsigned NOT NULL,
 `tag_id` int(11) unsigned NOT NULL,
 KEY `sourcecode_id` (`sourcecode_id`),
 KEY `tag_id` (`tag_id`),
 CONSTRAINT `sourcecodes_tags_ibfk_1` FOREIGN KEY (`tag_id`) REFERENCES `tags` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=latin1

Questo è il codice che genera l'errore:

ALTER TABLE sourcecodes_tags ADD FOREIGN KEY (sourcecode_id) REFERENCES sourcecodes (id) ON DELETE CASCADE ON UPDATE CASCADE

2
potresti anche pubblicare il tuo comando insert / update che provoca l'errore?
Zed,

64
le tue tabelle sono vuote quando aggiungi questa chiave esterna?
Zed,

12
prova a eseguire questa query per vedere se esiste qualche sourcecode_id che non sia un vero ID: SELECT sourcecode_id FROM sourcecodes_tags DOVE sourcecode_id NON È IN (SELEZIONA l'id DA sourcecodes AS tmp);
Zed,

11
Grazie Zed, questo era il problema in cui una delle tabelle conteneva dei dati. Pensandoci ora ha senso che stava fallendo perché c'erano cose che si riferivano a elementi inesistenti, ma non avrei mai immaginato. Grazie!
Zim,

2
Perché non riesce se la tabella è vuota?
theblackpearl,

Risposte:


226

Molto probabilmente la tua sourcecodes_tagstabella contiene sourcecode_idvalori che non esistono più nella tua sourcecodestabella. Devi prima sbarazzartene.

Ecco una query che può trovare quegli ID:

SELECT DISTINCT sourcecode_id FROM 
   sourcecodes_tags tags LEFT JOIN sourcecodes sc ON tags.sourcecode_id=sc.id 
WHERE sc.id IS NULL;

UPDATE sourcecodes_tags SET sourcecode_id = NULL WHERE sourcecode_id NOT IN (SELECT id FROM sourcecodes)dovrebbe aiutare a sbarazzarsi di quegli ID. Oppure, se nullnon è consentito sourcecode_id, quindi rimuovere quelle righe o aggiungere quei valori mancanti alla sourcecodestabella.
naXa,

Stavo pensando lo stesso ma, per me SELECT Tchild.id FROM Tchild INNER JOIN Tmain ON Tmain.id = Tchild.fk_id WHERE Tmain.id IS NULLnon restituisce nulla, quindi il problema è altrove !?
Meloman,

Ahh questo è stato il problema per me. Stavo cercando di correre UPDATE `homestead`.`automations` SET `deleted_at`=NULL WHERE deleted_at IS NOT NULL;, il che non implicava affatto una chiave esterna, quindi ero confuso. Ma il fatto che nella mia tabella dei contatti mancassero alcuni record a cui faceva riferimento la tabella delle automazioni ha causato questo "Codice di errore: 1452. Impossibile aggiungere o aggiornare una riga figlio: un vincolo di chiave esterna non riesce".
Ryan,

99

Ho avuto lo stesso problema con il mio database MySQL ma alla fine ho ottenuto una soluzione che ha funzionato per me.
Poiché nella mia tabella tutto andava bene dal punto di vista mysql (entrambe le tabelle dovrebbero usare il motore InnoDB e il tipo di dati di ogni colonna dovrebbe essere dello stesso tipo che prende parte al vincolo di chiave esterna).
L'unica cosa che ho fatto è stato disabilitare il controllo della chiave esterna e successivamente abilitarlo dopo aver eseguito l'operazione di chiave esterna.
I passaggi che ho preso:

SET foreign_key_checks = 0;
alter table tblUsedDestination add constraint f_operatorId foreign key(iOperatorId) references tblOperators (iOperatorId); Query
OK, 8 rows affected (0.23 sec) Records: 8  Duplicates: 0  Warnings: 0
SET foreign_key_checks = 1;

49
foreign_key_checks sono lì per un motivo. Se non è possibile aggiungere la chiave esterna perché viola il vincolo, è necessario prima correggere i dati. La disattivazione dei controlli e l'aggiunta della chiave ti lasciano in uno stato incoerente. I controlli di chiave esterna aggiungono sovraccarico, se non si desidera utilizzarli, utilizzare invece myisam.
cs_alumnus,

5
@AbuSadatMohammedYasin no, non dovrebbe: la domanda poneva "cosa sta succedendo" e questa risposta semplicemente non tenta di spiegarlo. Come cs_alumnus menzionato, c'è un problema più grande: tutti i nuovi valori che dovrebbero fare riferimento a un altro valore nell'altra tabella (come dovrebbe fare una chiave esterna ) potrebbero non indicare nulla, creando uno stato incoerente. La breve ed efficace spiegazione di Cayetano ti consente di trovare quali valori dovresti aggiornare prima di creare il vincolo in modo da non essere sorpreso da query che dovrebbero restituire valori che dovrebbero esistere!
Armfoot,

55

Utilizzare NOT INper trovare dove i vincoli sono vincolanti :

SELECT column FROM table WHERE column NOT IN 
(SELECT intended_foreign_key FROM another_table)

quindi, più specificamente:

SELECT sourcecode_id FROM sourcecodes_tags WHERE sourcecode_id NOT IN 
(SELECT id FROM sourcecodes)

EDIT: INe gli NOT INoperatori sono noti per essere molto più veloci degli JOINoperatori, oltre che molto più facili da costruire e ripetere.


1
Quindi, se lo capisco correttamente, possiamo aggiungere una chiave esterna a una tabella che contiene già dei dati, ma solo se esiste una riga figlio per ogni riga nella tabella padre? Se non ci sono righe figlio per ogni riga nella tabella padre (che è ciò che la tua query scopre), lo script di chiave esterna non riuscirà.
Vincent,

@Vincent se per tabella padre si intende la tabella a cui si fa riferimento, quindi sì! Pertanto con Cayetano's select ottieni tutte le righe che devi aggiornare / rimuovere dalla tabella "figlio" prima di aggiungere il nuovo vincolo (FK). Una volta che indicano tutti i valori in "another_table", allora sei a posto!
Armfoot,

23

Troncare le tabelle e quindi provare ad aggiungere il vincolo FK .

So che questa soluzione è un po 'imbarazzante ma funziona al 100%. Ma sono d'accordo sul fatto che questa non è una soluzione ideale per affrontare il problema, ma spero che sia di aiuto.


4
Non c'è bisogno di troncare tutto. "UPDATE sourcecodes_tags SET sourcecode_id = NULL DOVE sourcecode_id NON IN (SELEZIONA ID DA sourcecodes)" dovrebbe essere sufficiente. Oppure se null non è consentito in "sourcecode_id", quindi rimuovere quelle righe o aggiungere quei valori mancanti alla tabella "sourcecodes".
Torben,

1
A volte, se i dati aumentano il PK di autoincremento, ti costringe a troncare.
François Breton,

2
@ShankarDamodaran non so perché troncare il tavolo funzioni, ma questa soluzione ha funzionato bene per me. Sono stato in grado di far funzionare le mie relazioni ... GRAZIE!
Miz Akita

@MizAkita funziona perché elimina le righe che non hanno alcun valore corrispondente nell'altra tabella, consentendo la creazione del nuovo vincolo. Se trovi quelle righe e le aggiorni o le elimini (come il suggerimento di Cayetano ), non è necessario eliminare le altre righe ...
Armfoot,

@Armfoot: ho riscontrato questo problema durante l'aggiunta della prima riga alla tabella con chiave esterna. Quindi non avevo righe da cercare.
Krewetka,

16

Per me, questo problema era un po 'diverso e super facile da controllare e risolvere.

Devi assicurarti che ENTRAMBI dei tuoi tavoli siano InnoDB. Se una delle tabelle, vale a dire la tabella di riferimento è un MyISAM, il vincolo fallirà.

    SHOW TABLE STATUS WHERE Name =  't1';

    ALTER TABLE t1 ENGINE=InnoDB;

14

Ciò accade anche quando si imposta una chiave esterna su parent.id su child.column se child.column ha già un valore 0 e nessun valore parent.id è 0

Dovresti assicurarti che ogni child.column sia NULL o abbia un valore esistente in parent.id

E ora che ho letto la dichiarazione scritta nn, questo è ciò che sta convalidando.


14

Ho avuto lo stesso problema oggi. Ho testato quattro cose, alcune delle quali sono già state menzionate qui:

  1. Esistono valori nella colonna figlio che non esistono nella colonna padre (oltre a NULL, se la colonna figlio è nullable)

  2. Le colonne figlio e padre hanno lo stesso tipo di dati?

  3. C'è un indice nella colonna principale a cui fai riferimento? MySQL sembra richiederlo per motivi di prestazioni ( http://dev.mysql.com/doc/refman/5.5/en/create-table-foreign-keys.html )

  4. E questo ha risolto il problema per me: entrambi i tavoli hanno regole di confronto identiche?

Avevo un tavolo in UTF-8 e l'altro in iso-qualcosa. Non ha funzionato. Dopo aver modificato la tabella iso in regole di confronto UTF-8, i vincoli potrebbero essere aggiunti senza problemi. Nel mio caso, phpMyAdmin non ha nemmeno mostrato la tabella figlio in iso-codifica nel menu a discesa per creare il vincolo di chiave esterna.


7

Sembra che ci sia un valore non valido per la riga di colonna 0 che non è una chiave esterna valida, quindi MySQL non può impostare un vincolo di chiave esterna per esso.

Puoi seguire questi passaggi:

  1. Rilascia la colonna per cui hai provato a impostare il vincolo FK.

  2. Aggiungilo di nuovo e imposta il suo valore predefinito come NULL.

  3. Prova a impostare nuovamente un vincolo di chiave esterna.


5

Avevo lo stesso problema, ho controllato le righe delle mie tabelle e ho scoperto che c'era una certa incompatibilità con il valore dei campi che volevo definire una chiave esterna. Ho corretto quel valore, riprovato e il problema è stato risolto.


4

Finisco per eliminare tutti i dati nella mia tabella ed eseguo nuovamente alter. Funziona. Non brillante, ma consente di risparmiare molto tempo, in particolare l'applicazione è ancora in fase di sviluppo senza dati dei clienti.


4

prova questo

SET foreign_key_checks = 0;

ALTER TABLE sourcecodes_tags ADD FOREIGN KEY (sourcecode_id) REFERENCES sourcecodes (id) ON DELETE CASCADE ON UPDATE CASCADE

SET foreign_key_checks = 1;

2

Ho avuto questo stesso identico problema circa tre volte diverse. In ogni caso è stato perché uno (o più) dei miei record non erano conformi alla nuova chiave esterna. È possibile che si desideri aggiornare i record esistenti per seguire i vincoli di sintassi della chiave esterna prima di provare ad aggiungere la chiave stessa. L'esempio seguente dovrebbe generalmente isolare i record del problema:

SELECT * FROM (tablename)
    WHERE (candidate key) <> (proposed foreign key value) 
        AND (candidate key) <> (next proposed foreign key value)

ripetere AND (candidate key) <> (next proposed foreign key value)all'interno della query per ciascun valore nella chiave esterna.

Se hai un sacco di dischi questo può essere difficile, ma se la tua tabella è ragionevolmente piccola non dovrebbe richiedere troppo tempo. Non sono super sorprendente nella sintassi SQL, ma questo ha sempre isolato il problema per me.


2

Svuota i dati di entrambe le tabelle ed esegui il comando. Funzionerà.


VHanded ha dato la stessa risposta 3 anni fa. Speriamo che non ci siano dati importanti nelle tabelle ...
xlecoustillier,


1

Stavo preparando queste soluzioni e questo esempio potrebbe essere d'aiuto.

Il mio database ha due tabelle (email e credit_card) con chiavi primarie per i loro ID. Un'altra tabella (client) fa riferimento a questi ID tabelle come chiavi esterne. Ho un motivo per avere l'e-mail a parte i dati del cliente.

Per prima cosa inserisco i dati della riga per le tabelle referenziate (e-mail, credit_card), quindi ottengo l'ID per ciascuna, tali ID sono necessari nella terza tabella (client).

Se non inserisci prima le righe nelle tabelle di riferimento, MySQL non sarà in grado di fare le corrispondenze quando inserisci una nuova riga nella terza tabella che fa riferimento alle chiavi esterne.

Se si inseriscono prima le righe di riferimento per le tabelle di riferimento, quindi la riga che fa riferimento a chiavi esterne, non si verifica alcun errore.

Spero che questo ti aiuti.


mysql> inserisci nei valori email (email) ('xxx@yyy.com'); mysql> inserisci nei valori ndtc (ndtc, year, month) ('1111222233334444', '2000', '01'); mysql> inserisci nel cliente (nombres, apellidos, telefono, idNDTC, idEmail) i valori ('myname', 'myapp', '5555555555', 1,1);
Sostanza

1

Assicurati che il valore sia nell'altra tabella, altrimenti otterrai questo errore, nella colonna corrispondente assegnata.

Pertanto, se viene assegnata la colonna, viene assegnata a un ID riga di un'altra tabella, assicurarsi che sia presente una riga nella tabella, altrimenti verrà visualizzato questo errore.


1

puoi provare questo esempio

 START TRANSACTION;
 SET foreign_key_checks = 0;
 ALTER TABLE `job_definers` ADD CONSTRAINT `job_cities_foreign` FOREIGN KEY 
 (`job_cities`) REFERENCES `drop_down_lists`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
 SET foreign_key_checks = 1;
 COMMIT;

Nota: se si utilizza phpmyadmin, deselezionare Abilita controlli chiave esterna

come esempio inserisci qui la descrizione dell'immagine

spero che questa solitudine risolva il tuo problema :)


1

Devi solo rispondere a una domanda:

La tua tabella sta già memorizzando dati? (Soprattutto la tabella includeva la chiave esterna.)

Se la risposta è sì, l'unica cosa che devi fare è eliminare tutti i record, quindi sei libero di aggiungere qualsiasi chiave esterna alla tua tabella.

Elimina istruzione: da figlio (che include la tabella delle chiavi esterne) alla tabella principale.

Il motivo per cui non è possibile aggiungere una chiave esterna dopo l'immissione dei dati è dovuto all'incongruenza della tabella, come gestirete una nuova chiave esterna nella precedente tabella riempita di dati?

Se la risposta è no, seguire le altre istruzioni.


0
UPDATE sourcecodes_tags
SET sourcecode_id = NULL
WHERE sourcecode_id NOT IN (
  SELECT id FROM sourcecodes);

dovrebbe aiutare a sbarazzarsi di quegli ID. Oppure, se nullnon è consentito sourcecode_id, quindi rimuovere quelle righe o aggiungere quei valori mancanti alla sourcecodestabella.


0

Ho avuto lo stesso problema e ho trovato la soluzione, posizionandola NULLinvece NOT NULLsulla colonna chiave esterna. Ecco una query:

ALTER TABLE `db`.`table1`
ADD COLUMN `col_table2_fk` INT UNSIGNED NULL,
ADD INDEX `col_table2_fk_idx` (`col_table2_fk` ASC),
ADD CONSTRAINT `col_table2_fk1`
FOREIGN KEY (`col_table2_fk`)
REFERENCES `db`.`table2` (`table2_id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION;

MySQL ha eseguito questa query!


0

Nel mio caso, ho creato una nuova tabella con la stessa struttura, creato le relazioni con le altre tabelle, quindi estratto i dati in CSV dalla vecchia tabella che presenta il problema, quindi importato il CSV nella nuova tabella e disabilitato il controllo della chiave esterna e disabilitato l'interruzione dell'importazione, tutti i miei dati vengono inseriti nella nuova tabella che non ha alcun problema con successo, quindi eliminata la vecchia tabella.

Ha funzionato per me.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.