Il vincolo di chiave esterna fasullo fallisce


110

Ottengo questo messaggio di errore:

ERRORE 1217 (23000) alla riga 40: impossibile eliminare o aggiornare una riga padre: un vincolo di chiave esterna non riesce

... quando provo a eliminare una tabella:

DROP TABLE IF EXISTS `area`;

... definito così:

CREATE TABLE `area` (
  `area_id` char(3) COLLATE utf8_spanish_ci NOT NULL,
  `nombre_area` varchar(30) COLLATE utf8_spanish_ci NOT NULL,
  `descripcion_area` varchar(100) COLLATE utf8_spanish_ci NOT NULL,
  PRIMARY KEY (`area_id`),
  UNIQUE KEY `nombre_area_UNIQUE` (`nombre_area`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_spanish_ci;

La cosa divertente è che ho già eliminato tutte le altre tabelle nello schema che hanno chiavi esterne contro area. In realtà, il database è vuoto ad eccezione della areatabella.

Come può avere righe figlie se non ci sono altri oggetti nel database? Per quanto ne so, InnoDB non consente chiavi esterne su altri schemi, vero?

(Posso anche eseguire un RENAME TABLE area TO something_elsecomando: -?)


È possibile che la tabella faccia parte di una relazione di integrità referenziale in un altro schema?
Raj More

Ho altre copie dell'app quindi è sempre possibile. Tuttavia, la sintassi che uso è fondamentalmente CONSTRAINT fk_servicio_area1 FOREIGN KEY (area_id) REFERENCES area (area_id), cioè, nessun nome di schema sul riferimento alla tabella: -?
Álvaro González

Risposte:


101

Due possibilità:

  1. C'è una tabella all'interno di un altro schema ("database" nella terminologia mysql) che ha un riferimento FK
  2. Il dizionario dati interno di innodb non è sincronizzato con quello di mysql.

Puoi vedere quale tabella era (una di queste, comunque) facendo un "SHOW ENGINE INNODB STATUS" dopo che il rilascio fallisce.

Se risulta essere il secondo caso, dovrei scaricare e ripristinare l'intero server se puoi.

MySQL 5.1 e versioni successive ti daranno il nome della tabella con FK nel messaggio di errore.


1
Non riesco più a riprodurre il problema. Il dizionario non sincronizzato si distingue come una probabile ragione. Lo proverò il giorno e vedrò quali SHOW ENGINE INNODB STATUSrapporti.
Álvaro González

3
Grazie per questa risposta! Avevo un tavolo molti a molti che faceva ancora riferimento al tavolo che non potevamo eliminare, quindi ho dovuto prima eliminare quel tavolo.
Christian Oudard

5
SHOW ENGINE INNODB STATUS elenca l'ultimo errore di chiave esterna in "LATEST FOREIGN KEY ERROR". Questo ha un timestamp.
bbrame

potrebbe esserci una tabella con ancora una chiave di riferimento per la tabella dell'oggetto. nel mio caso era così.
RT

Risparmiato molto tempo. Eliminato il database in "LATEST FOREIGN KEY ERROR"
Sand1512

121

Su richiesta, ora come risposta ...

Quando si utilizza MySQL Query Browser o phpMyAdmin, sembra che venga aperta una nuova connessione per ogni query ( bugs.mysql.com/bug.php?id=8280 ), rendendo necessario scrivere tutte le istruzioni drop in una query, ad es.

SET FOREIGN_KEY_CHECKS=0; 
DROP TABLE my_first_table_to_drop; 
DROP TABLE my_second_table_to_drop; 
SET FOREIGN_KEY_CHECKS=1; 

Dove SET FOREIGN_KEY_CHECKS=1serve come misura di sicurezza aggiuntiva ...


2
Per coloro che creano un dump usando phpMyAdmin, c'è un'opzione "Disabilita i controlli delle chiavi esterne" che si aggiungerà automaticamente SET FOREIGN_KEY_CHECKS=0;all'inizio del dump.
Mike

Sembra che phpMyAdmin abbia implementato questa adorabile funzionalità, ora sto aspettando che mysqlWorkbench faccia lo stesso! :)
Karlis Rode

@CodeMed FYI, ho accettato la risposta di MarkR perché fornisce una spiegazione per il problema che ha senso, anche se ammetto che non ho potuto verificarlo poiché non ho affrontato lo stesso problema nei 6 anni successivi, nemmeno una volta. Questa e le risposte precedenti forniscono una soluzione alternativa (ottimo per quello buono) ma non affrontano davvero la domanda in sé e poiché puoi accettare solo una risposta, ho dovuto scegliere.
Álvaro González

1
Attenzione: questa non è una soluzione ma solo una soluzione alternativa per l'uomo pigro. Dopo averlo utilizzato (con i record su altre tabelle che puntano alla tabella rilasciata), sperimenterai chiavi esterne penzolanti che interrompono fatalmente la coerenza (la C in ACID ) del tuo database e le tue applicazioni inizieranno a lanciare eccezioni ovunque. Sei stato avvertito.
bekce

Anche se sono sicuro che l'avvertimento dovrebbe essere compreso e tenuto in considerazione, questa soluzione ha funzionato per me, in una situazione in cui ero sicuro che stavo anche facendo cadere tutte le tabelle che puntavano alle tabelle con i fastidiosi vincoli di chiave esterna.
user1147171

47

Disabilita il controllo delle chiavi esterne

SET FOREIGN_KEY_CHECKS=0

62
Il comando corretto sembra essere SET FOREIGN_KEY_CHECKS=0e risolve il messaggio di errore. Hai qualche idea sul motivo per cui è necessario? Le chiavi esterne vengono memorizzate nella cache anche dopo che le tabelle sono sparite?
Álvaro González

1
Beh, a dire il vero, non ho idea del motivo per cui si verifica un tale problema, ma assicurati di disabilitare il controllo delle chiavi ogni volta che apporti modifiche o aggiornamenti enormi. Mi è successo più volte, lasciandomi senza dormire per giorni.
Flakron Bytyqi

55
Assicurati di farlo SET FOREIGN_KEY_CHECKS=1;dopo aver finito!
pedro_sland

5
Quando si utilizza MySQL Query Browser o phpMyAdmin, sembra che venga aperta una nuova connessione per ogni query ( bugs.mysql.com/bug.php?id=8280 ), rendendo necessario scrivere tutte le istruzioni drop in una query, ad es. SET FOREIGN_KEY_CHECKS=0; DROP TABLE my_first_table_to_drop; DROP TABLE my_second_table_to_drop; SET FOREIGN_KEY_CHECKS=1; Dove SET FOREIGN_KEY_CHECKS = 1 serve come misura di sicurezza aggiuntiva ...
Karlis Rode

1
@KarlisRode, Bravo per il commento su phpMyAdmin. Se dovessi metterlo come risposta, lo farei +1.
Sablefoste

28

da questo blog :

Puoi disabilitare temporaneamente i controlli delle chiavi esterne:

SET FOREIGN_KEY_CHECKS=0;

Assicurati solo di ripristinarli una volta che hai finito di scherzare:

SET FOREIGN_KEY_CHECKS=1;

Bella risposta mentre stavo sviluppando in locale :)
Adelin

È una soluzione alternativa valida (posso confermare che funziona) ma il post del blog collegato non parla davvero dello scenario in questa domanda (un database che è già vuoto tranne una tabella).
Álvaro González

6

si spera che funzioni

SET foreign_key_checks = 0; DROP TABLE table name; SET foreign_key_checks = 1;


Sì, funziona, come più volte è stato menzionato prima ;-)
Álvaro González

1

Su Rails, è possibile eseguire le seguenti operazioni utilizzando rails console:

connection = ActiveRecord::Base.connection
connection.execute("SET FOREIGN_KEY_CHECKS=0;")

0

Forse hai ricevuto un errore prima di lavorare con questa tabella. Puoi rinominare la tabella e provare a rimuoverla di nuovo.

ALTER TABLE `area` RENAME TO `area2`;
DROP TABLE IF EXISTS `area2`;

0

ho trovato una soluzione semplice, esporta il database, modifica ciò che vuoi modificare in un editor di testo, quindi importalo. Fatto


4
Questa è una soluzione interessante, che probabilmente non dovrebbe effettivamente accadere. Invece, tutto ciò che deve essere modificato dovrebbe essere fatto tramite il DBMS. La modifica di un dump del database in un editor di testo sembra una strada matura per i problemi.
Brandon Anzaldi

1
Non capisco davvero cosa ti piace. Scaricare il database, rimuovere il CREATE TABLEcodice e caricare nuovamente il dump ... non farà in modo che MySQL rimuova la tabella. E se intendi ripristinare il dump in un nuovo database ... Se vuoi cancellare tutte le tabelle come me, un database appena creato sarà già vuoto. Se vuoi mantenere alcune tabelle, la SET FOREIGN_KEY_CHECKS=0soluzione alternativa menzionata ovunque qui funziona bene ed è più semplice; e probabilmente non è necessario modificare il dump in ogni caso poiché la nuova copia dei dati potrebbe non avere un dizionario dei dati non sincronizzato.
Álvaro González

-1

Impossibile eliminare o aggiornare una riga padre: un vincolo di chiave esterna non riesce ( table1. user_role, CONSTRAINT FK143BF46A8dsfsfds@#5A6BD60FOREIGN KEY ( user_id) REFERENCES user( id))

Quello che ho fatto in due semplici passaggi. per prima cosa elimino la riga figlio nella tabella figlio come

mysql> elimina da table2 dove role_id = 2 && user_id = 20;

Query OK, 1 riga interessata (0,10 sec)

e secondo passaggio come eliminare il genitore

elimina dalla tabella1 dove id = 20;

Query OK, 1 riga interessata (0,12 sec)

Con questo risolvo il problema che significa Elimina figlio quindi Elimina genitore

spero che tu abbia capito :)


Si prega di leggere di nuovo la domanda. Non puoi rimuovere una tabella che non esiste.
Álvaro González

in questo scenario possiamo rimuovere il vincolo della chiave esterna, quindi provare a eliminare la tabella. possiamo rilasciare una chiave esterna come questa ALTER TABLE <TABLE_NAME> DROP CONSTRAINT <FOREIGN_KEY_NAME>
Aadil Masavir
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.