Échec de la contrainte de clé étrangère fausse

110

Je reçois ce message d'erreur:

ERREUR 1217 (23000) à la ligne 40: impossible de supprimer ou de mettre à jour une ligne parente: une contrainte de clé étrangère échoue

... quand j'essaye de déposer une table:

DROP TABLE IF EXISTS `area`;

... défini comme ceci:

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;

Le plus drôle, c'est que j'ai déjà supprimé toutes les autres tables du schéma qui ont des clés étrangères area. En fait, la base de données est vide à l'exception de la areatable.

Comment peut-il avoir des lignes enfants s'il n'y a pas d'autre objet dans la base de données? Autant que je sache, InnoDB n'autorise pas les clés étrangères sur d'autres schémas, n'est-ce pas?

(Je peux même exécuter une RENAME TABLE area TO something_elsecommande: -?)

Álvaro González
la source
Est-il possible que la table fasse partie d'une relation référentielle-intégrité dans un autre schéma?
Raj More
J'ai d'autres copies de l'application, donc c'est toujours possible. Cependant, la syntaxe que j'utilise est essentiellement CONSTRAINT fk_servicio_area1 FOREIGN KEY (area_id) REFERENCES area (area_id), à savoir, aucun nom de schéma sur la référence de table: -?
Álvaro González

Réponses:

101

Deux possibilités:

  1. Il y a une table dans un autre schéma ("base de données" dans la terminologie mysql) qui a une référence FK
  2. Le dictionnaire de données interne innodb n'est pas synchronisé avec celui de mysql.

Vous pouvez voir de quelle table il s'agissait (l'un d'entre eux, en tout cas) en effectuant un "SHOW ENGINE INNODB STATUS" après l'échec de la suppression.

Si cela s'avère être le dernier cas, je viderais et restaurerais tout le serveur si vous le pouvez.

MySQL 5.1 et supérieur vous donnera le nom de la table avec le FK dans le message d'erreur.

MarkR
la source
1
Je ne peux plus reproduire le problème. Le dictionnaire désynchronisé est une raison probable. Je vais le tester jour et voir quels SHOW ENGINE INNODB STATUSrapports.
Álvaro González
3
Merci pour cette réponse! J'avais une table plusieurs-à-plusieurs faisant toujours référence à la table que nous ne pouvions pas supprimer, j'ai donc dû supprimer cette table en premier.
Christian Oudard
5
SHOW ENGINE INNODB STATUS répertorie la dernière erreur de clé étrangère sous "LATEST FOREIGN KEY ERROR". Cela a un horodatage.
bbrame le
il pourrait y avoir une table ayant encore une clé de référence à la table sujet. c'était dans mon cas, comme ça.
RT
Gain de temps. La base de données a été abandonnée sous "LATEST FOREIGN KEY ERROR"
Sand 1512
121

Sur demande, maintenant comme réponse ...

Lorsque vous utilisez MySQL Query Browser ou phpMyAdmin, il semble qu'une nouvelle connexion soit ouverte pour chaque requête ( bugs.mysql.com/bug.php?id=8280 ), ce qui rend nécessaire d'écrire toutes les instructions drop dans une requête, par exemple.

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

Où le SET FOREIGN_KEY_CHECKS=1sert de mesure de sécurité supplémentaire ...

Karlis Rode
la source
2
Pour ceux qui créent un vidage en utilisant phpMyAdmin, il existe une option "Désactiver les vérifications de clé étrangère" qui s'ajoutera automatiquement SET FOREIGN_KEY_CHECKS=0;au début du vidage.
Mike
On dirait que phpMyAdmin a implémenté cette belle fonctionnalité, maintenant j'attends que mysqlWorkbench fasse de même! :)
Karlis Rode
@CodeMed FYI, j'ai accepté la réponse de MarkR parce qu'elle fournit une explication au problème qui a du sens - même si j'avoue ne pas pouvoir le vérifier car je n'ai pas rencontré ce même problème dans les 6 années suivantes, pas même une seule fois. Ceci et les réponses précédentes fournissent une solution de contournement (super pour ça) mais ne répondent pas vraiment à la question elle-même et puisque vous ne pouvez accepter qu'une seule réponse, j'ai dû choisir.
Álvaro González
1
Attention: ce n'est pas une solution mais seulement une solution de contournement de l'homme paresseux. Après avoir utilisé ceci (avec des enregistrements sur d'autres tables pointant vers la table supprimée), vous rencontrerez des clés étrangères pendantes qui cassent fatalement la cohérence (le C dans ACID ) de votre base de données et vos applications commenceront à lancer des exceptions partout. Tu as été prévenu.
bekce
Même si je suis sûr que l'avertissement de bekce doit être compris et pris en compte, cette solution a fonctionné pour moi, dans une situation où j'étais convaincu que je supprimais également toutes les tables qui pointaient vers les tables avec les contraintes de clé étrangère gênantes.
user1147171
47

Désactiver la vérification des clés étrangères

SET FOREIGN_KEY_CHECKS=0
Flakron Bytyqi
la source
62
La commande correcte semble être SET FOREIGN_KEY_CHECKS=0et elle corrige le message d'erreur. Avez-vous une idée de la raison pour laquelle cela est nécessaire? Les clés étrangères sont-elles mises en cache même après la disparition des tables?
Álvaro González
1
Eh bien, pour dire la vérité, je n'ai aucune idée de la raison pour laquelle un tel problème se pose, mais assurez-vous de désactiver la vérification des clés à chaque fois que vous effectuez des modifications ou des mises à jour importantes. Cela m'est arrivé plusieurs fois, me laissant sans sommeil pendant des jours.
Flakron Bytyqi
55
Assurez- SET FOREIGN_KEY_CHECKS=1;vous après avoir terminé!
pedro_sland
5
Lorsque vous utilisez MySQL Query Browser ou phpMyAdmin, il semble qu'une nouvelle connexion soit ouverte pour chaque requête ( bugs.mysql.com/bug.php?id=8280 ), ce qui rend nécessaire d'écrire toutes les instructions drop dans une requête, par exemple. SET FOREIGN_KEY_CHECKS=0; DROP TABLE my_first_table_to_drop; DROP TABLE my_second_table_to_drop; SET FOREIGN_KEY_CHECKS=1; Où le SET FOREIGN_KEY_CHECKS = 1 sert de mesure de sécurité supplémentaire ...
Karlis Rode
1
@KarlisRode, Bravo pour le commentaire sur phpMyAdmin. Si vous deviez répondre à cette question, je donnerais +1.
Sablefoste
28

de ce blog :

Vous pouvez désactiver temporairement les vérifications de clé étrangère:

SET FOREIGN_KEY_CHECKS=0;

Assurez-vous simplement de les restaurer une fois que vous avez fini de déconner:

SET FOREIGN_KEY_CHECKS=1;
JackD
la source
Belle réponse alors que je développais sur local :)
Adelin
C'est une solution de contournement valide (je peux confirmer que cela fonctionne) mais l'entrée de blog liée ne parle pas vraiment du scénario de cette question (une base de données déjà vide, sauf pour une table).
Álvaro González
6

j'espère que son travail

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

M_ Fa
la source
Oui, cela fonctionne, car plusieurs fois cela a été mentionné auparavant ;-)
Álvaro González
1

Sur les rails, on peut faire ce qui suit en utilisant rails console:

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

Vous avez peut-être déjà reçu une erreur lors de l'utilisation de cette table. Vous pouvez renommer la table et essayer de la supprimer à nouveau.

ALTER TABLE `area` RENAME TO `area2`;
DROP TABLE IF EXISTS `area2`;
Vadim Pluzhinsky
la source
0

J'ai trouvé une solution simple, exporter la base de données, la modifier ce que vous souhaitez modifier dans un éditeur de texte, puis l'importer. Terminé

Abdulrahman K
la source
4
C'est une solution intéressante, qui ne devrait probablement pas arriver. Au lieu de cela, tout ce qui doit être modifié doit être fait via le SGBD. La modification d'un vidage de base de données dans un éditeur de texte semble être une voie mûre pour les problèmes.
Brandon Anzaldi
1
Je ne comprends pas vraiment ce que vous aimez. Vider la base de données, supprimer le CREATE TABLEcode et charger à nouveau le vidage ... ne fera pas supprimer la table par MySQL. Et si vous voulez dire restaurer le vidage dans une nouvelle base de données ... Si vous voulez effacer toutes les tables comme moi, une base de données nouvellement créée sera déjà vide. Si vous souhaitez conserver certaines tables, la SET FOREIGN_KEY_CHECKS=0solution de contournement mentionnée partout ici fonctionne correctement et est plus simple; et vous n'avez probablement pas besoin de modifier le vidage de toute façon puisque la nouvelle copie de vos données n'aura probablement pas de dictionnaire de données désynchronisé.
Álvaro González
-1

Impossible de supprimer ou de mettre à jour une ligne parente: une contrainte de clé étrangère échoue ( table1. user_role, CONSTRAINT FK143BF46A8dsfsfds@#5A6BD60FOREIGN KEY ( user_id) REFERENCES user( id))

Ce que j'ai fait en deux étapes simples. je supprime d'abord la ligne enfant dans la table enfant comme

mysql> supprimer de la table2 où role_id = 2 && user_id = 20;

Requête OK, 1 ligne affectée (0,10 s)

et la deuxième étape consiste à supprimer le parent

supprimer de table1 où id = 20;

Requête OK, 1 ligne affectée (0,12 s)

Par cela, je résous le problème, ce qui signifie supprimer l'enfant puis supprimer le parent

J'espère que vous l'avez. :)

Aadil Masavir
la source
Veuillez relire la question. Vous ne pouvez pas supprimer une table qui n'existe pas.
Álvaro González
dans ce scénario, nous pouvons supprimer la contrainte de clé étrangère puis essayer de supprimer la table. nous pouvons supprimer la clé étrangère comme ceci ALTER TABLE <TABLE_NAME> DROP CONSTRAINT <FOREIGN_KEY_NAME>
Aadil Masavir