243 votes

Erreur Mysql 1452 - Impossible d'ajouter ou de mettre à jour une ligne enfant : une contrainte de clé étrangère échoue.

J'ai un problème un peu étrange. J'essaie d'ajouter une clé étrangère à une table qui fait référence à une autre, mais cela échoue pour une raison quelconque. Avec mes connaissances limitées de MySQL, la seule chose qui pourrait être suspecte est qu'il y a une clé étrangère sur une table différente qui fait référence à celle que j'essaie de référencer.

J'ai fait un SHOW CREATE TABLE sur les deux tables, sourcecodes_tags est la table avec la clé étrangère, sourcecodes est la table référencée.

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

C'est le code qui génère l'erreur :

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

2 votes

Pourriez-vous également afficher votre commande d'insertion/mise à jour qui entraîne l'erreur ?

66 votes

Vos tables sont-elles vides lorsque vous ajoutez cette clé étrangère ?

12 votes

Essayez d'exécuter cette requête pour voir s'il y a un Sourcecode_id qui n'est pas un vrai ID : SELECT sourcecode_id FROM sourcecodes_tags WHERE sourcecode_id NOT IN (SELECT id FROM sourcecodes AS tmp) ;

229voto

nos Points 102226

Il est fort probable que votre sourcecodes_tags Le tableau contient sourcecode_id qui n'existe plus dans votre sourcecodes la table. Tu dois d'abord te débarrasser de ceux-là.

Voici une requête qui peut trouver ces identifiants :

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

0 votes

UPDATE sourcecodes_tags SET sourcecode_id = NULL WHERE sourcecode_id NOT IN (SELECT id FROM sourcecodes) devrait aider à se débarrasser de ces identifiants. Ou si null n'est pas autorisé dans sourcecode_id puis supprimez ces lignes ou ajoutez ces valeurs manquantes à la base de données. sourcecodes table.

0 votes

Je pensais la même chose mais, pour moi SELECT Tchild.id FROM Tchild INNER JOIN Tmain ON Tmain.id = Tchild.fk_id WHERE Tmain.id IS NULL ne renvoie rien, donc le problème est ailleurs ! ?

0 votes

Ahh, c'était le problème pour moi. J'essayais d'exécuter UPDATE `homestead`.`automations` SET `deleted_at`=NULL WHERE deleted_at IS NOT NULL; qui n'impliquait pas du tout de clé étrangère, j'étais donc confus. Mais le fait qu'il manquait à ma table de contacts certains enregistrements auxquels la table d'automatisation faisait référence a provoqué ce "Error Code : 1452. Impossible d'ajouter ou de mettre à jour une ligne enfant : une contrainte de clé étrangère échoue".

105voto

Prakash Points 459

J'ai eu le même problème avec ma base de données MySQL mais finalement, j'ai trouvé une solution qui a fonctionné pour moi.
Puisque dans ma table tout allait bien du point de vue de mysql (les deux tables devraient utiliser le moteur InnoDB et le type de données de chaque colonne devrait être du même type qui prend part à la contrainte de clé étrangère).
La seule chose que j'ai faite a été de désactiver la vérification de la clé étrangère, puis de l'activer après avoir effectué l'opération de clé étrangère.
Les étapes que j'ai franchies :

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;

53 votes

Les vérifications des clés étrangères sont là pour une raison. Si vous ne pouvez pas ajouter la clé étrangère parce qu'elle viole la contrainte, vous devez d'abord corriger les données. Désactiver les vérifications puis ajouter la clé vous laisse dans un état incohérent. Les vérifications de clés étrangères ajoutent des frais généraux, si vous ne voulez pas les utiliser, utilisez myisam à la place.

5 votes

@AbuSadatMohammedYasin non, cela ne devrait pas : la question demandait " que se passe-t-il ? " et cette réponse ne tente tout simplement pas de l'expliquer. Comme cs_alumnus l'a mentionné, il y a un problème plus important : toutes les nouvelles valeurs qui devraient faire référence à une autre valeur dans l'autre table (comme une Étranger devrait faire) peut ne rien indiquer, créant ainsi un état incohérent. L'explication courte et efficace de Cayetano vous permet de trouver les valeurs à mettre à jour avant de créer la contrainte. Vous ne serez donc pas surpris par des requêtes qui renvoient des valeurs qui devraient exister !

0 votes

Dans mon cas, la colonne du parent avait une longueur de 25 caractères alors que celle des enfants avait 30 caractères. L'augmentation de la longueur des caractères à 30 a réglé le problème. Merci de m'avoir orienté dans la bonne direction.

56voto

Utilisez NOT IN pour trouver où sont les contraintes contraignant :

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

donc, plus précisément :

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

EDIT : IN y NOT IN sont connus pour être beaucoup plus rapides que les JOIN ainsi que beaucoup plus facile à construire et à répéter.

1 votes

Donc, si je comprends bien, nous pouvons ajouter une clé étrangère à une table qui contient déjà des données, mais seulement si une ligne enfant existe pour chaque ligne de la table parent ? S'il n'y a pas de rangée enfant pour chaque rangée de la table parent (ce que votre requête découvre), alors la clé étrangère script échouera.

0 votes

@Vincent si par table parente vous voulez dire la table référencée, alors oui ! Par conséquent, avec la sélection de Cayetano, vous obtenez toutes les lignes que vous devez mettre à jour/supprimer de votre table "enfant" avant d'ajouter la nouvelle contrainte (FK). Une fois qu'elles pointent toutes vers des valeurs dans la table "another_table", vous êtes prêt à partir !

23voto

Shankar Damodaran Points 39934

Tronquez les tables et essayez ensuite d'ajouter la contrainte FK. .

Je sais que cette solution est un peu maladroite mais elle fonctionne à 100%. Je reconnais que ce n'est pas une solution idéale pour traiter le problème, mais j'espère qu'elle vous aidera.

4 votes

Il n'est pas nécessaire de tout tronquer. "UPDATE sourcecodes_tags SET sourcecode_id = NULL WHERE sourcecode_id NOT IN (SELECT id FROM sourcecodes)" devrait suffire. Ou si null n'est pas autorisé dans "sourcecode_id", alors supprimez ces lignes ou ajoutez ces valeurs manquantes à la table "sourcecodes".

1 votes

Parfois, si les données incrémentent l'autoincrément PK, cela vous oblige à tronquer.

2 votes

@ShankarDamodaran pas sûr de savoir pourquoi la troncature de la table fonctionne mais cette solution a bien fonctionné pour moi. J'ai réussi à faire fonctionner mes relations... MERCI !

16voto

fyrye Points 119

Cela se produit également lors de la définition d'une clé étrangère de parent.id à child.column si child.column a déjà une valeur de 0 et qu'aucune valeur de parent.id n'est 0.

Vous devez vous assurer que chaque colonne child.column est NULL ou a une valeur qui existe dans parent.id.

Et maintenant que je lis la déclaration que Nos a écrite, c'est ce qu'il valide.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X