web-dev-qa-db-fra.com

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

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

Voici une image de mes relations de table, générée via phpMyAdmin: Relationships

J'ai effectué une requête 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

Ce serait formidable si quelqu'un pouvait me dire ce qui se passe ici, je n'ai pas eu de formation officielle ni quoi que ce soit avec MySQL :)

Merci.

Edit: 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
227
Zim

Il est fort probable que votre table sourcecodes_tags contient des valeurs sourcecode_id qui n'existent plus dans votre table sourcecodes. Vous devez vous débarrasser de ces premiers.

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;
220
nos

J'ai eu le même problème avec ma base de données mysql mais finalement j'ai eu 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 et prendre 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.
Étapes que j'ai prises:

mysql> SET foreign_key_checks = 0;

mysql> 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

mysql> SET foreign_key_checks = 1;
91
Prakash

Utilisez NOT IN pour trouver où les contraintes sontcontraignant:

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

alors, plus spécifiquement:

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

EDIT: Les opérateurs IN et NOT IN sont connus pour être beaucoup plus rapides que les opérateurs JOIN, ainsi que beaucoup plus faciles à construire et à répéter.

55
Ryan Ward

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

Je sais que cette solution est un peu délicate, mais cela fonctionne à 100%. Mais je conviens que ce n’est pas une solution idéale pour régler un problème, mais j’espère que cela aidera.

23

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

Vous devez vous assurer que vos tables sont toutes deux 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;
15
zmonteca

J'ai eu le même problème aujourd'hui. J'ai testé pour 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 parente que vous référencez? MySQL semble en avoir besoin pour des raisons de performances ( http://dev.mysql.com/doc/refman/5.5/fr/create-table-foreign-keys.html )

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

J'avais une table en utf-8 et l'autre en iso-quelque chose. Cela n'a pas fonctionné. Une fois la classification iso-table remplacée par la classification 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 codage ISO dans le menu déroulant pour la création de la contrainte de clé étrangère.

14
Michael Helwig

Cela se produit également lorsque vous définissez une clé étrangère sur parent.id sur child.column si le paramètre child.column a la valeur 0 et qu'aucune valeur parent.id n'est définie sur 0

Vous devez vous assurer que chaque colonne enfant est NULL ou que sa valeur existe dans parent.id.

Et maintenant que j'ai lu la déclaration que nos écrites, c'est ce qu'il valide.

14
fyrye

Il semble qu'il existe une valeur non valide pour la colonne, telle que 0, qui ne soit pas une clé étrangère valide. Par conséquent, MySQL ne peut pas définir 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 la contrainte de clé étrangère pour elle.

7
Milad

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

5
Mostafa -T

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;
4
Carlo Guevarra

Je finis par supprimer toutes les données de ma table et de relancer alter. Ça marche. Pas génial, mais cela fait gagner beaucoup de temps, surtout que votre application est encore en phase de développement, sans aucune donnée client.

4
VHanded

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 qu'ils respectent les contraintes de syntaxe de la clé étrangère avant d'essayer d'ajouter la clé elle-même. L'exemple suivant devrait généralement isoler les enregistrements de problèmes:

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

répétez 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 relativement petite, cela ne devrait pas prendre trop de temps. Je ne suis pas génial avec la syntaxe SQL, mais cela a toujours isolé le problème pour moi.

2
mopsyd

J'avais cette erreur en utilisant Laravel et eloquent, essayer de faire un lien de clé étrangère provoquerait un 1452. Le problème était le manque de données dans la table liée.

Veuillez voir ici un exemple: http://mstd.eu/index.php/2016/12/02/laravel-eloquent-integrity-constraint-violation-1452-foreign-key-constraint/

2
twigg

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

2
vijayrana

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

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

D'abord, j'insère les données de ligne pour les tables référencées (email, credit_card), puis vous obtenez l'ID pour chacune d'entre elles. 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 faisant 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.

1
SyntheticMeshwork

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

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

1
Kingsley Mitchell

J'ai une solution, il vous suffit de répondre à une question:

Votre table contient-elle déjà des données? En particulier, la table comprenait une clé étrangère.

Si la réponse est oui, la seule chose à faire est de supprimer tout l'enregistrement et vous êtes alors libre d'ajouter n'importe quelle clé étrangère dans votre table.

Instruction de suppression: de l'enfant (qui inclut la table de clé étrangère) à la table parent.

La raison pour laquelle vous ne pouvez pas ajouter de clé étrangère après les entrées de données est due à l'incohérence de la table. Que ferez-vous avec la nouvelle clé étrangère de l'ancienne table remplie de données?

Si non, alors suivez les instructions des autres.

1
nobody
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, supprimez ces lignes ou ajoutez ces valeurs manquantes à la table sourcecodes.

0
naXa

J'ai eu le même problème et trouvé la solution, plaçant NULL au lieu de NOT NULL sur 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!

0
akelec