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

237

J'ai un petit problème étrange. J'essaie d'ajouter une clé étrangère à une table qui en fait référence à une autre, mais elle échoue pour une raison quelconque. Avec ma connaissance limitée de MySQL, la seule chose qui pourrait être suspecte est qu'il existe une clé étrangère sur une table différente référençant celle que j'essaie de référencer.

J'ai fait une SHOW CREATE TABLErequête sur les deux tables, sourcecodes_tagsc'est la table avec la clé étrangère, sourcecodesc'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
Zim
la source
2
pourriez-vous également publier votre commande d'insertion / mise à jour qui entraîne l'erreur?
Zed
64
vos tables sont-elles vides lorsque vous ajoutez cette clé étrangère?
Zed
12
essayez d'exécuter cette requête pour voir s'il y a un identifiant de code source qui n'est pas un véritable identifiant: SELECT identifiant de code source FROM sourcecodes_tags OERE sourcecode_id PAS DANS (SELECT identifiant FROM code source AS tmp);
Zed
11
Merci Zed, c'était le problème que l'une des tables contenait des données. En y réfléchissant maintenant, il est logique que cela échoue parce qu'il y avait des choses qui faisaient référence à des éléments inexistants, mais je n'aurais jamais deviné cela. Merci!
Zim
2
Pourquoi échoue-t-il si la table est vide?
theblackpearl

Réponses:

226

Il est fort probable que votre sourcecodes_tagstable contienne des sourcecode_idvaleurs qui n'existent plus dans votre sourcecodestable. Vous devez d'abord vous en débarrasser.

Voici une requête qui peut trouver ces ID:

SELECT DISTINCT sourcecode_id FROM 
   sourcecodes_tags tags LEFT JOIN sourcecodes sc ON tags.sourcecode_id=sc.id 
WHERE sc.id IS NULL;
non
la source
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 nulln'est pas autorisé dans sourcecode_id, supprimez ces lignes ou ajoutez ces valeurs manquantes au sourcecodestableau.
naXa
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 NULLne retourne rien, donc le problème est ailleurs!?
Meloman
Ahh c'était le problème pour moi. J'essayais de courir UPDATE `homestead`.`automations` SET `deleted_at`=NULL WHERE deleted_at IS NOT NULL;, ce qui ne comportait pas du tout de clé étrangère, donc j'étais confus. Mais le fait qu'il manquait à ma table de contacts certains enregistrements auxquels la table d'automatisations faisait référence l'a amenée à lancer ce "Code d'erreur: 1452. Impossible d'ajouter ou de mettre à jour une ligne enfant: une contrainte de clé étrangère échoue".
Ryan
99

J'ai eu le même problème avec ma base de données MySQL mais finalement, j'ai obtenu une solution qui fonctionnait pour moi.
Puisque dans ma table tout allait bien du point de vue 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 participe à 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 et de l'activer plus tard après avoir effectué l'opération de clé étrangère.
Étapes que j'ai prises:

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;
Prakash
la source
49
Foreign_key_checks sont là pour une raison. Si vous ne pouvez pas ajouter la clé étrangère car 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 souhaitez pas les utiliser, utilisez plutôt myisam.
cs_alumnus
5
@AbuSadatMohammedYasin non, cela ne devrait pas: la question demandait "ce qui se passe" et cette réponse ne tente tout simplement pas de l'expliquer. Comme mentionné cs_alumnus, 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 clé étrangère devrait le faire) peuvent pointer vers rien, créant un état incohérent. L'explication courte et efficace de Cayetano vous permet de trouver les valeurs que vous devez mettre à jour avant de créer la contrainte afin que vous ne soyez pas surpris par les requêtes qui devraient renvoyer des valeurs qui devraient exister!
Armfoot
55

Utilisez NOT INpour trouver où les contraintes contraignent :

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: INet les NOT INopérateurs sont connus pour être beaucoup plus rapides que les JOINopérateurs, ainsi que beaucoup plus faciles à construire et à répéter.

Ryan Ward
la source
1
Donc, si je comprends bien, nous pouvons ajouter une clé étrangère à une table qui contient déjà des données, mais uniquement s'il existe une ligne enfant pour chaque ligne de la table parent? S'il n'y a pas de lignes enfants pour chaque ligne dans la table parent (ce que découvre votre requête), le script de clé étrangère échouera.
Vincent
@Vincent si par table parent vous entendez la table référencée, alors oui! Par conséquent, avec Cayetano's select, 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'ils pointent tous vers des valeurs dans la "another_table", alors vous êtes prêt à partir!
Armfoot
23

Tronquez les tables, puis essayez d'ajouter la contrainte FK .

Je sais que cette solution est un peu gênante mais elle fonctionne à 100%. Mais je suis d'accord que ce n'est pas une solution idéale pour résoudre un problème, mais j'espère que cela aide.

Shankar Damodaran
la source
4
Pas besoin 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", supprimez ces lignes ou ajoutez ces valeurs manquantes à la table "sourcecodes".
Torben
1
Parfois, si les données incrémentent l'auto-incrémentation PK, cela vous oblige à tronquer.
François Breton
2
@ ShankarDamodaran ne sais pas pourquoi la troncature de la table fonctionne mais cette solution a bien fonctionné pour moi. J'ai pu faire travailler mes relations ... MERCI!
MizAkita
@MizAkita cela fonctionne car il supprime les lignes qui n'ont pas de valeur correspondante dans l'autre table, ce qui permet de créer la nouvelle contrainte. Si vous venez de trouver ces lignes et de les mettre à jour ou de les supprimer (comme la suggestion de Cayetano ), vous n'avez pas besoin de supprimer les autres lignes ...
Armfoot
@Armfoot - J'ai eu ce problème lors de l'ajout de la première ligne à la table avec une clé étrangère. Je n'avais donc aucune ligne à rechercher.
Krewetka
16

Pour moi, ce problème était un peu différent et super facile à vérifier et à résoudre.

Vous devez vous assurer que LES DEUX de vos tables sont InnoDB. Si l'une des tables, à savoir la table de référence est un MyISAM, la contrainte échouera.

    SHOW TABLE STATUS WHERE Name =  't1';

    ALTER TABLE t1 ENGINE=InnoDB;
zmonteca
la source
14

Cela se produit également lorsque vous définissez une clé étrangère sur parent.id sur child.column si child.column a déjà une valeur de 0 et qu'aucune valeur 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 j'ai lu la déclaration que nous avons écrite, c'est ce qu'il valide.

fyrye
la source
14

J'ai eu le même problème aujourd'hui. J'ai testé quatre choses, certaines d'entre elles ont déjà été mentionnées ici:

  1. Y a-t-il des valeurs dans votre colonne enfant qui n'existent pas dans la colonne parent (à part NULL, si la colonne enfant est nullable)

  2. Les colonnes enfant et parent ont-elles le même type de données?

  3. Y a-t-il un index sur la colonne parent à laquelle vous faites référence? MySQL semble l'exiger pour des raisons de performances ( http://dev.mysql.com/doc/refman/5.5/en/create-table-foreign-keys.html )

  4. Et celui-ci l'a résolu pour moi: les deux tables ont-elles un classement identique?

J'avais une table en UTF-8 et l'autre en iso-quelque chose. Ça n'a pas marché. Après avoir changé l'iso-table en classement UTF-8, les contraintes peuvent être ajoutées sans problème. Dans mon cas, phpMyAdmin n'a même pas montré la table enfant en iso-encoding dans la liste déroulante pour créer la contrainte de clé étrangère.

Michael Helwig
la source
7

Il semble qu'il y ait une valeur non valide pour la ligne de colonne 0 qui n'est pas une clé étrangère valide, donc MySQL ne peut pas lui assigner de contrainte de clé étrangère.

Vous pouvez suivre ces étapes:

  1. Supprimez la colonne pour laquelle vous avez essayé de définir la contrainte FK.

  2. Ajoutez-le à nouveau et définissez sa valeur par défaut sur NULL.

  3. Essayez de définir à nouveau une contrainte de clé étrangère.

Milad Rahimi
la source
5

J'aurais le même problème, j'ai vérifié les lignes de mes tables et j'ai trouvé qu'il y avait une incompatibilité avec la valeur des champs que je voulais définir une clé étrangère. J'ai corrigé ces valeurs, réessayé et le problème a été résolu.

Mostafa -T
la source
4

Je finis par supprimer toutes les données de ma table et j'exécute à nouveau alter. Ça marche. Pas la plus brillante, mais cela fait gagner beaucoup de temps, en particulier votre application est toujours en phase de développement sans aucune donnée client.

VHanded
la source
4

essaye ça

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;
Carlo Guevarra
la source
2

J'ai eu exactement le même problème environ trois fois. Dans chaque cas, c'était parce qu'un (ou plusieurs) de mes enregistrements n'était pas conforme à la nouvelle clé étrangère. Vous souhaiterez peut-être mettre à jour vos enregistrements existants pour respecter les contraintes de syntaxe de la clé étrangère avant d'essayer d'ajouter la clé elle-même. L'exemple suivant doit généralement isoler les enregistrements de problème:

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

répéter AND (candidate key) <> (next proposed foreign key value)dans votre requête pour chaque valeur de la clé étrangère.

Si vous avez une tonne d'enregistrements, cela peut être difficile, mais si votre table est raisonnablement petite, cela ne devrait pas prendre trop de temps. Je ne suis pas super étonnant dans la syntaxe SQL, mais cela a toujours isolé le problème pour moi.

mopsyd
la source
2

Videz les données de vos tables et exécutez la commande. Ça va marcher.

vijayrana
la source
VHanded a donné la même réponse il y a 3 ans. Espérons qu'il n'y avait pas de données importantes dans les tableaux ...
xlecoustillier
1

Je préparais ces solutions et cet exemple peut aider.

Ma base de données a deux tables (email et carte de crédit) avec des clés primaires pour leurs identifiants. Une autre table (client) fait référence à ces identifiants de tables comme des clés étrangères. J'ai une raison d'avoir l'e-mail en dehors des données client.

J'insère d'abord les données de ligne pour les tables référencées (email, credit_card) puis vous obtenez l'ID pour chacune, ces ID sont nécessaires dans la troisième table (client).

Si vous n'insérez pas d'abord les lignes dans les tables référencées, MySQL ne pourra pas faire les correspondances lorsque vous insérez une nouvelle ligne dans la troisième table qui fait référence aux clés étrangères.

Si vous insérez d'abord les lignes référencées pour les tables référencées, puis la ligne qui fait référence aux clés étrangères, aucune erreur ne se produit.

J'espère que cela t'aides.

SubstanceMX
la source
mysql> insérer dans les valeurs de l'email (email) ('[email protected]'); mysql> insérer dans les valeurs ndtc (ndtc, année, mois) ('1111222233334444', '2000', '01'); mysql> insérer dans la clientèle (nombres, apellidos, telefono, idNDTC, idEmail) les valeurs ('myname', 'myapp', '5555555555', 1,1);
SubstanceMX
1

Assurez-vous que la valeur est dans l'autre table, sinon vous obtiendrez cette erreur, dans la colonne correspondante affectée.

Donc, si une colonne est affectée à un ID de ligne d'une autre table, assurez-vous qu'il y a une ligne dans la table, sinon cette erreur apparaîtra.

Kingsley Mitchell
la source
1

vous pouvez essayer cet exemple

 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;

Remarque: si vous utilisez phpmyadmin, décochez simplement Activer les vérifications de clés étrangères

comme exemple entrez la description de l'image ici

j'espère que cette solution résout votre problème :)

Fouad Mekkey
la source
1

Il vous suffit de répondre à une question:

Votre table stocke-t-elle déjà des données? (Surtout le tableau comprenait une clé étrangère.)

Si la réponse est oui, alors la seule chose que vous devez faire est de supprimer tous les enregistrements, vous êtes alors libre d'ajouter n'importe quelle clé étrangère à votre table.

Supprimer l'instruction: de l'enfant (qui inclut la table de clés étrangères) à la table parent.

La raison pour laquelle vous ne pouvez pas ajouter de clé étrangère après la saisie de données est due à l'incohérence de la table, comment allez-vous gérer une nouvelle clé étrangère sur l'ancienne table remplie de données?

Si la réponse est non, suivez les autres instructions.

personne
la source
0
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 nulln'est pas autorisé dans sourcecode_id, supprimez ces lignes ou ajoutez ces valeurs manquantes au sourcecodestableau.

naXa
la source
0

J'ai eu le même problème et j'ai trouvé une solution, en plaçant NULLau lieu de NOT NULLsur la colonne de clé étrangère. Voici une requête:

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 a exécuté cette requête!

akelec
la source
0

Dans mon cas, j'ai créé une nouvelle table avec la même structure, créé les relations avec les autres tables, puis extrait les données dans CSV de l'ancienne table qui a le problème, puis importé le CSV dans la nouvelle table et désactivé la vérification des clés étrangères et désactivé l'interruption de l'importation, toutes mes données sont insérées dans la nouvelle table qui n'a pas de problème avec succès, puis supprimées l'ancienne table.

Ça a marché pour moi.

Shamal Sabah
la source