MySQL no puede eliminar el índice necesario en una restricción de clave externa


155

Necesito ALTERAR mi base de datos existente para agregar una columna. En consecuencia, también quiero actualizar el campo ÚNICO para abarcar esa nueva columna. Estoy tratando de eliminar el índice actual pero sigo recibiendo el errorMySQL 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

¿Asumiendo UNIQUE KEY AIDen mytable?
Mike Purcell

Respuestas:


228

Tienes que soltar la clave foránea. Las claves externas en MySQL crean automáticamente un índice en la tabla (había una pregunta SO sobre el tema).

ALTER TABLE mytable DROP FOREIGN KEY mytable_ibfk_1 ; 

12
Es posible que desee agregarlo nuevamente después de soltar el índice: ALTERAR TABLA mytableAGREGAR RESTRICCIÓN mytable_ibfk_1CLAVE EXTRANJERA ( AID) REFERENCIAS mytable_a( ID) EN ELIMINAR CASCADA;
laffuste

8
Eso es genial, pero ¿qué puedo hacer si mi FOREIGN KEYrestricción es anónima?
Pehat

@Pehat revisa mi respuesta a continuación stackoverflow.com/a/54145440/2305119
thyzz

1
Nota: la clave externa puede no ser tan obvia. Para encontrar todas las claves externas relacionadas con una tabla y columna, puede usar esta consulta: dba.stackexchange.com/questions/102371/…
charlax

84

Paso 1

Listar clave externa (TEN EN CUENTA que es diferente del nombre del índice)

SHOW CREATE TABLE  <Table Name>

El resultado le mostrará el nombre de la clave externa.

Formato:

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

Paso 2

Tecla soltar (externa / primaria / clave)

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

Paso 3

Suelta el índice.


18

Si quiere decir que puede hacer esto:

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.

Pero entonces:

ALTER TABLE mytable
DROP KEY AID ;

da error


Puede soltar el índice y crear uno nuevo en una ALTER TABLEdeclaración:

ALTER TABLE mytable
DROP KEY AID ,
ADD UNIQUE KEY AID (AID, BID, CID, DID);

8

Como debe tener un índice en un campo de clave externa, puede crear un índice simple en el campo 'AID'

CREATE INDEX aid_index ON mytable (AID);

y solo entonces suelte el índice único 'AID'

ALTER TABLE mytable DROP INDEX AID;

7

Una clave foránea siempre requiere un índice. Sin un índice que imponga la restricción, se requeriría un escaneo completo de la tabla en la tabla referenciada para cada clave insertada o actualizada en la tabla de referencia. Y eso tendría un impacto inaceptable en el rendimiento. Esto tiene las siguientes 2 consecuencias:

  • Al crear una clave foránea, la base de datos verifica si existe un índice. Si no, se creará un índice. Por defecto, tendrá el mismo nombre que la restricción.
  • Cuando solo hay un índice que se puede usar para la clave externa, no se puede descartar. Si realmente no desea eliminarlo, debe eliminar la restricción de clave externa o crear otro índice para ello primero.

1
tienes la teoría de que faltan otras respuestas.
Dennis

1
Entonces: si tiene un índice único compuesto (varias columnas en una restricción única) no puede eliminar la clave AB única a menos que tenga un índice para A y B. Si obtiene este error, otra tabla está utilizando el índice de la columna A o B, y tendrá que agregarlos antes de poder eliminar de forma segura el AB único.
Robin De Schepper

@RobinDeSchepper Buen comentario. Y cuando se usan índices únicos compuestos, el orden de los campos no es importante para el índice único, pero podría ser importante para una clave externa. Un índice único en A, B puede ser utilizado por una clave externa en A, pero no por una clave externa en B.
Stefan Mondelaers

2

Creo que esta es una manera fácil de eliminar el índice.

set FOREIGN_KEY_CHECKS=1;

ALTER TABLE mytable DROP INDEX AID;

set FOREIGN_KEY_CHECKS=0;

2
Creo que intercambiaste habilitar y deshabilitar los cheques. En la cima esperaría FOREIGN_KEY_CHEK=0y al final FOREIGN_KEY_CHEK=1.
romor

0

En mi caso, eliminé la clave externa y aún no podía eliminar el índice. Eso fue porque había otra tabla que tenía una clave externa para esta tabla en los mismos campos. Después de que solté la clave foránea en la otra tabla, pude soltar los índices en esta tabla.


0

si desea soltar una columna de clave externa (que tiene una restricción), primero debe soltar la clave externa y luego soltar la columna, cuando suelte la clave externa, no tiene que pasar todo el nombre, simplemente pase la clave externa nombre de columna:

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

Más detalles sobre:

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

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.