Impossible de supprimer ou de mettre à jour une ligne parent: une contrainte de clé étrangère échoue

170

En faisant:

DELETE FROM `jobs` WHERE `job_id` =1 LIMIT 1 

Il erreurs:

#1451 - Cannot delete or update a parent row: a foreign key constraint fails 
(paymesomething.advertisers, CONSTRAINT advertisers_ibfk_1 FOREIGN KEY 
(advertiser_id) REFERENCES jobs (advertiser_id))

Voici mes tableaux:

CREATE TABLE IF NOT EXISTS `advertisers` (
  `advertiser_id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(255) NOT NULL,
  `password` char(32) NOT NULL,
  `email` varchar(128) NOT NULL,
  `address` varchar(255) NOT NULL,
  `phone` varchar(255) NOT NULL,
  `fax` varchar(255) NOT NULL,
  `session_token` char(30) NOT NULL,
  PRIMARY KEY (`advertiser_id`),
  UNIQUE KEY `email` (`email`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 AUTO_INCREMENT=2 ;


INSERT INTO `advertisers` (`advertiser_id`, `name`, `password`, `email`, `address`, `phone`, `fax`, `session_token`) VALUES
(1, 'TEST COMPANY', '', '', '', '', '', '');

CREATE TABLE IF NOT EXISTS `jobs` (
  `job_id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `advertiser_id` int(11) unsigned NOT NULL,
  `name` varchar(255) NOT NULL,
  `shortdesc` varchar(255) NOT NULL,
  `longdesc` text NOT NULL,
  `address` varchar(255) NOT NULL,
  `time_added` int(11) NOT NULL,
  `active` tinyint(1) NOT NULL,
  `moderated` tinyint(1) NOT NULL,
  PRIMARY KEY (`job_id`),
  KEY `advertiser_id` (`advertiser_id`,`active`,`moderated`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 AUTO_INCREMENT=2 ;


INSERT INTO `jobs` (`job_id`, `advertiser_id`, `name`, `shortdesc`, `longdesc`, `address`, `active`, `moderated`) VALUES
(1, 1, 'TEST', 'TESTTEST', 'TESTTESTES', '', 0, 0);

ALTER TABLE `advertisers`
  ADD CONSTRAINT `advertisers_ibfk_1` FOREIGN KEY (`advertiser_id`) REFERENCES `jobs` (`advertiser_id`);
Steven
la source

Réponses:

108

En l'état, vous devez supprimer la ligne de la table des annonceurs avant de pouvoir supprimer la ligne de la table des emplois à laquelle elle fait référence. Ce:

ALTER TABLE `advertisers`
  ADD CONSTRAINT `advertisers_ibfk_1` FOREIGN KEY (`advertiser_id`) 
      REFERENCES `jobs` (`advertiser_id`);

... est en fait le contraire de ce qu'il devrait être. Dans l'état actuel des choses, cela signifie que vous devez avoir un enregistrement dans le tableau des emplois avant les annonceurs. Vous devez donc utiliser:

ALTER TABLE `jobs`
  ADD CONSTRAINT `advertisers_ibfk_1` FOREIGN KEY (`advertiser_id`) 
      REFERENCES `advertisers` (`advertiser_id`);

Une fois que vous avez corrigé la relation de clé étrangère, votre instruction de suppression fonctionnera.

Poneys OMG
la source
3
Dans la première ligne: ne pensez-vous pas que ce devrait être "qu'il référence" au lieu de "qui le référence"? Ou ai-je mal compris comment la terminologie des références est censée fonctionner?
Abraham Philip
6
@AbrahamPhilip Je pensais la même chose. les annonceurs font référence aux emplois.
keyer
270

Le moyen le plus simple serait de désactiver la vérification de la clé étrangère; effectuez les modifications, puis réactivez la vérification de la clé étrangère.

SET FOREIGN_KEY_CHECKS=0; -- to disable them
SET FOREIGN_KEY_CHECKS=1; -- to re-enable them
Alino Manzi
la source
171
Ce n'est pas une solution au problème, mais plutôt une solution de contournement qui peut ne pas être souhaitée.
madfriend
20
Dans mon cas: je viens d'exécuter un gros fichier SQL et l'une des instructions finales a échoué, donc je veux simplement supprimer toutes les tables, corriger l'erreur de syntaxe et réexécuter, ce qui en fait exactement ce que je recherchais.
ekerner
1
Si vous vouliez faire cela, pourquoi ne pas simplement supprimer toutes les contraintes?
Sablefoste
1
C'est utile lorsque vous faites quelque chose comme:REPLACE INTO tab_with_constraint ...
Maciek Łoziński
5
La seule raison de voter pour cette réponse est si vous voulez simplement que votre code cesse de vous crier dessus et se faufile plus profondément dans les spaghettis sans comprendre le code que vous écrivez. La raison d'avoir des clés étrangères en premier lieu est d'appliquer l'intégrité référentielle. Si vous devez les désactiver pour arrêter votre code, vous voudrez probablement repenser vos clés étrangères, au lieu de les désactiver.
cytinus
38

Dans le cadre de votre conception actuelle (éventuellement défectueuse), vous devez supprimer la ligne de la table des annonceurs avant de pouvoir supprimer la ligne dans la table des emplois à laquelle elle fait référence.

Vous pouvez également configurer votre clé étrangère de telle sorte qu'une suppression dans la table parente entraîne la suppression automatique des lignes des tables enfants. C'est ce qu'on appelle une suppression en cascade. Cela ressemble à quelque chose comme ceci:

ALTER TABLE `advertisers`
ADD CONSTRAINT `advertisers_ibfk_1`
FOREIGN KEY (`advertiser_id`) REFERENCES `jobs` (`advertiser_id`)
ON DELETE CASCADE;

Cela dit, comme d'autres l'ont déjà souligné, votre clé étrangère semble devoir aller dans l'autre sens puisque la table des annonceurs contient vraiment la clé primaire et la table des emplois contient la clé étrangère. Je le réécrirais comme ceci:

ALTER TABLE `jobs`
ADD FOREIGN KEY (`advertiser_id`) REFERENCES `advertisers` (`advertiser_id`);

Et la suppression en cascade ne sera pas nécessaire.

Asaph
la source
18

Si vous souhaitez supprimer une table, vous devez exécuter la requête suivante en une seule étape

SET FOREIGN_KEY_CHECKS = 0; DROP TABLE nom_table;

Abin John
la source
13

J'ai essayé la solution mentionnée par @Alino Manzi mais cela n'a pas fonctionné pour moi sur les tables liées à WordPress utilisant wpdb.

puis j'ai modifié le code comme ci-dessous et cela a fonctionné

SET FOREIGN_KEY_CHECKS=OFF; //disabling foreign key

//run the queries which are giving foreign key errors

SET FOREIGN_KEY_CHECKS=ON; // enabling foreign key
Moh .S
la source
6

Je pense que votre clé étrangère est à l'envers. Essayer:

ALTER TABLE 'jobs'
ADD CONSTRAINT `advertisers_ibfk_1` FOREIGN KEY (`advertiser_id`) REFERENCES `advertisers` (`advertiser_id`)
Tom H
la source
5

S'il y a plus d'un emploi ayant le même advertiser_id, votre clé étrangère doit être:

ALTER TABLE `jobs`
ADD CONSTRAINT `advertisers_ibfk_1` 
FOREIGN KEY (`advertiser_id`) 
REFERENCES `advertisers` (`advertiser_id`);

Sinon (si c'est l'inverse dans votre cas), si vous voulez que les lignes de l'annonceur soient automatiquement supprimées si la ligne de la tâche est supprimée, ajoutez l'option `` ON DELETE CASCADE '' à la fin de votre clé étrangère:

ALTER TABLE `advertisers`
ADD CONSTRAINT `advertisers_ibfk_1` 
FOREIGN KEY (`advertiser_id`) 
REFERENCES `jobs` (`advertiser_id`)
ON DELETE CASCADE;

Découvrez les contraintes de clé étrangère

Utilisateur SO
la source
3

Vous devez le supprimer par ordre Il y a des dépendances dans les tables

Ran Adler
la source
2

Lorsque vous créez une base de données ou créez des tables

Vous devez ajouter cette ligne en haut script créer une base de données ou une table

SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=1;

Vous souhaitez maintenant supprimer des enregistrements de la table? alors vous écrivez comme

SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=1;
DELETE FROM `jobs` WHERE `job_id` =1 LIMIT 1

Bonne chance!

Quy Le
la source
2

Que diriez-vous de cette alternative que j'ai utilisée: autorisez la clé étrangère à être NULL , puis choisissez ON DELETE SET NULL .

Personnellement, je préfère utiliser à la fois " ON UPDATE CASCADE " et " ON DELETE SET NULL " pour éviter des complications inutiles, mais sur votre configuration, vous voudrez peut-être une approche différente. De plus, l'utilisation de valeurs de clé étrangère NULL peut entraîner des complications, car vous ne saurez pas ce qui s'y est exactement passé. Ce changement doit donc être en relation étroite avec le fonctionnement de votre code d'application.

J'espère que cela t'aides.

Marius Cucuruz
la source
2

J'ai eu ce problème dans la migration laravel aussi
l'ordre des tables de dépôt dans la méthode down () importe

Schema::dropIfExists('groups');
Schema::dropIfExists('contact');

peut ne pas fonctionner, mais si vous modifiez l'ordre, cela fonctionne.

Schema::dropIfExists('contact');
Schema::dropIfExists('groups');
Amin
la source
1

si vous avez besoin de soutenir le client dès que possible et que vous n'avez pas accès à

FOREIGN_KEY_CHECKS

afin que l'intégrité des données puisse être désactivée:

1) supprimer la clé étrangère

ALTER TABLE `advertisers` 
DROP FOREIGN KEY `advertisers_ibfk_1`;

2) Activez votre opération de suppression via sql ou api

3) ajoutez la clé étrangère au schéma

ALTER TABLE `advertisers`
  ADD CONSTRAINT `advertisers_ibfk_1` FOREIGN KEY (`advertiser_id`) REFERENCES `jobs` (`advertiser_id`);

cependant, il s'agit d'un correctif, donc c'est à vos risques et périls, car le principal défaut d'une telle approche est qu'elle est nécessaire par la suite pour conserver l'intégrité des données manuellement.

Oleksii Kyslytsyn
la source
0

Vous pouvez créer un déclencheur pour supprimer les lignes référencées avant de supprimer le travail.

    DELIMITER $$
    CREATE TRIGGER before_jobs_delete 
        BEFORE DELETE ON jobs
        FOR EACH ROW 
    BEGIN
        delete from advertisers where advertiser_id=OLD.advertiser_id;
    END$$
    DELIMITER ;
Patch92
la source
0

Le principal problème avec cette erreur Error Code: 1451. Cannot delete or update a parent row: a foreign key constraint failsest qu'il ne vous permet pas de savoir quelle table contient l'échec FK, il est donc difficile de résoudre le conflit.

Si vous utilisez MySQL ou similaire, j'ai découvert que vous pouvez créer un diagramme ER pour votre base de données, vous pouvez alors examiner et supprimer en toute sécurité tout conflit déclenchant l'erreur.

  1. Utilisez MySQL Workbench
  2. Cliquez sur Database -> Reverse Engineering
  3. Sélectionnez un bon connection
  4. Ensuite jusqu'à la fin, n'oubliez pas de sélectionner databaseet tablesque vous devez examiner
  5. Maintenant que vous avez le diagramme ER, vous pouvez voir quelle table a un conflit FK
Ng Sek Long
la source
0

Fondamentalement, la raison derrière ce type d'erreur est finalement que vous essayez de supprimer un tupple qui a une clé primaire (table racine) et cette clé primaire est utilisée dans la table enfant comme clé étrangère. Dans ce scénario, pour supprimer les données de la table parent, vous devez supprimer les données de la table enfant (dans lesquelles la clé étrangère est utilisée). Merci

kishan99
la source
0

Cela m'est également arrivé et en raison d'une dépendance et d'une référence à d'autres tables, je n'ai pas pu supprimer l'entrée. Ce que j'ai fait, c'est ajouté une colonne de suppression (de type booléen) à la table. La valeur de ce champ indique si l'élément est marqué pour suppression ou non. Si marqué pour suppression, ne pas chercher / utiliser; sinon, utilisez-le.

Tariq Kamal
la source
-1

Peut-être devriez-vous essayer ON DELETE CASCADE


la source
34
Ajouter aveuglément une suppression en cascade (qui détruira les données) sans comprendre le problème est à peu près la pire chose que l'on puisse faire.
Tom H