MySQL ne peut pas supprimer l'index nécessaire dans une contrainte de clé étrangère

156

J'ai besoin de MODIFIER ma base de données existante pour ajouter une colonne. Par conséquent, je souhaite également mettre à jour le champ UNIQUE pour englober cette nouvelle colonne. J'essaie de supprimer l'index actuel mais continue à recevoir l'erreurMySQL Cannot drop index needed in a foreign key constraint

CREATE TABLE mytable_a (
ID          TINYINT NOT NULL AUTO_INCREMENT PRIMARY KEY,
Name        VARCHAR(255) NOT NULL,
UNIQUE(Name)
) ENGINE=InnoDB;

CREATE TABLE mytable_b (
ID          TINYINT NOT NULL AUTO_INCREMENT PRIMARY KEY,
Name        VARCHAR(255) NOT NULL,
UNIQUE(Name)
) ENGINE=InnoDB;

CREATE TABLE mytable_c (
ID          TINYINT NOT NULL AUTO_INCREMENT PRIMARY KEY,
Name        VARCHAR(255) NOT NULL,
UNIQUE(Name)
) ENGINE=InnoDB;


CREATE TABLE `mytable` (
  `ID` int(11) NOT NULL AUTO_INCREMENT,
  `AID` tinyint(5) NOT NULL,
  `BID` tinyint(5) NOT NULL,
  `CID` tinyint(5) NOT NULL,
  PRIMARY KEY (`ID`),
  UNIQUE KEY `AID` (`AID`,`BID`,`CID`),
  KEY `BID` (`BID`),
  KEY `CID` (`CID`),
  CONSTRAINT `mytable_ibfk_1` FOREIGN KEY (`AID`) REFERENCES `mytable_a` (`ID`) ON DELETE CASCADE,
  CONSTRAINT `mytable_ibfk_2` FOREIGN KEY (`BID`) REFERENCES `mytable_b` (`ID`) ON DELETE CASCADE,
  CONSTRAINT `mytable_ibfk_3` FOREIGN KEY (`CID`) REFERENCES `mytable_c` (`ID`) ON DELETE CASCADE
) ENGINE=InnoDB;




mysql> ALTER TABLE mytable DROP INDEX AID;
ERROR 1553 (HY000): Cannot drop index 'AID': needed in a foreign key constraint
user391986
la source
En supposant UNIQUE KEY AIDsur ma table?
Mike Purcell

Réponses:

228

Vous devez supprimer la clé étrangère. Les clés étrangères dans MySQL créent automatiquement un index sur la table (il y avait une question SO sur le sujet).

ALTER TABLE mytable DROP FOREIGN KEY mytable_ibfk_1 ; 
Brian Fisher
la source
12
Vous souhaiterez peut-être le rajouter après avoir supprimé l'index: ALTER TABLE mytableADD CONSTRAINT mytable_ibfk_1FOREIGN KEY ( AID) REFERENCES mytable_a( ID) ON DELETE CASCADE;
laffuste
8
C'est génial, mais que puis-je faire si ma FOREIGN KEYcontrainte était anonyme?
Pehat
@Pehat vérifiez ma réponse ci-dessous stackoverflow.com/a/54145440/2305119
thyzz
1
Remarque: la clé étrangère peut ne pas être aussi évidente. Pour trouver toutes les clés étrangères liées à une table et une colonne, vous pouvez utiliser cette requête: dba.stackexchange.com/questions/102371/…
charlax
84

Étape 1

Liste des clés étrangères (notez qu'elle est différente du nom d'index)

SHOW CREATE TABLE  <Table Name>

Le résultat vous montrera le nom de la clé étrangère.

Format:

CONSTRAINT `FOREIGN_KEY_NAME` FOREIGN KEY (`FOREIGN_KEY_COLUMN`) REFERENCES `FOREIGN_KEY_TABLE` (`id`),

Étape 2

Clé de suppression (étrangère / primaire / clé)

ALTER TABLE <Table Name> DROP FOREIGN KEY <Foreign key name>

Étape 3

Supprimez l'index.

Abhishek Goel
la source
18

Si vous voulez dire que vous pouvez faire ceci:

CREATE TABLE mytable_d (
ID          TINYINT NOT NULL AUTO_INCREMENT PRIMARY KEY,
Name        VARCHAR(255) NOT NULL,
UNIQUE(Name)
) ENGINE=InnoDB;


ALTER TABLE mytable
ADD COLUMN DID tinyint(5) NOT NULL,
ADD CONSTRAINT mytable_ibfk_4 
      FOREIGN KEY (DID) 
        REFERENCES mytable_d (ID) ON DELETE CASCADE;

 > OK.

Mais alors:

ALTER TABLE mytable
DROP KEY AID ;

donne une erreur.


Vous pouvez supprimer l'index et en créer un nouveau en une seule ALTER TABLEinstruction:

ALTER TABLE mytable
DROP KEY AID ,
ADD UNIQUE KEY AID (AID, BID, CID, DID);
ypercubeᵀᴹ
la source
8

Parce que vous devez avoir un index sur un champ de clé étrangère, vous pouvez simplement créer un index simple sur le champ 'AID'

CREATE INDEX aid_index ON mytable (AID);

et alors seulement, supprimez l'index unique 'AID'

ALTER TABLE mytable DROP INDEX AID;
Eli DM
la source
7

Une clé étrangère nécessite toujours un index. Sans un index, l'application de la contrainte nécessiterait une analyse complète de la table sur la table référencée pour chaque clé insérée ou mise à jour dans la table de référence. Et cela aurait un impact inacceptable sur les performances. Cela a les 2 conséquences suivantes:

  • Lors de la création d'une clé étrangère, la base de données vérifie si un index existe. Sinon, un index sera créé. Par défaut, il aura le même nom que la contrainte.
  • Lorsqu'il n'y a qu'un seul index qui peut être utilisé pour la clé étrangère, il ne peut pas être supprimé. Si vous ne voulez vraiment pas le supprimer, vous devez soit supprimer la contrainte de clé étrangère, soit créer un autre index pour elle en premier.
Stefan Mondelaers
la source
1
vous avez la théorie que d'autres réponses manquaient.
Dennis
1
Donc: si vous avez un index unique composé (plusieurs colonnes dans une contrainte unique), vous ne pouvez pas supprimer la clé AB unique sauf si vous avez un index pour A et B.Si vous obtenez cette erreur, une autre table utilise l'index de la colonne A ou B, et vous devrez les ajouter avant de pouvoir supprimer en toute sécurité l'AB unique.
Robin De Schepper
@RobinDeSchepper Bonne remarque. Et lors de l'utilisation d'index uniques composés, l'ordre des champs n'est pas important pour l'index unique, mais il peut être important pour une clé étrangère. Un index unique sur A, B peut être utilisé par une clé étrangère sur A, mais pas par une clé étrangère sur B.
Stefan Mondelaers
2

Je pense que c'est un moyen facile de supprimer l'index.

set FOREIGN_KEY_CHECKS=1;

ALTER TABLE mytable DROP INDEX AID;

set FOREIGN_KEY_CHECKS=0;
Ram E Sh
la source
2
Je pense que vous avez échangé l'activation et la désactivation des chèques. Au sommet je m'attendrais FOREIGN_KEY_CHEK=0et à la fin FOREIGN_KEY_CHEK=1.
romor
0

Dans mon cas, j'ai laissé tomber la clé étrangère et je ne pouvais toujours pas supprimer l'index. C'était parce qu'il y avait encore une autre table qui avait une clé étrangère à cette table sur les mêmes champs. Après avoir déposé la clé étrangère sur l'autre table, j'ai pu supprimer les index sur cette table.

jav
la source
0

si vous voulez supprimer une colonne de clé étrangère (avec une contrainte), vous devez d'abord supprimer la clé étrangère, puis déposer la colonne, lorsque vous déposez la clé étrangère, vous n'avez pas à passer tout le nom, passez simplement la clé étrangère nom de colonne:

$table->dropForeign(['currency_id']);
$table->dropColumn('currency_id');

plus de détails sur:

https://laravel.com/docs/6.x/migrations#foreign-key-constraints

OMR
la source