¿Cómo deshabilitar temporalmente una restricción de clave externa en MySQL?

651

¿Es posible deshabilitar temporalmente las restricciones en MySQL?

Tengo dos modelos de Django, cada uno con una ForeignKey para el otro. Eliminar instancias de un modelo devuelve un error debido a la restricción ForeignKey:

cursor.execute("DELETE FROM myapp_item WHERE n = %s", n)
transaction.commit_unless_managed()  #a foreign key constraint fails here

cursor.execute("DELETE FROM myapp_style WHERE n = %s", n)
transaction.commit_unless_managed()

¿Es posible desactivar temporalmente las restricciones y eliminar de todos modos?

jul
fuente
3
O no entiendo lo que quieres hacer, o lo que estás tratando de hacer es muy, muy, muy feo . Incluso si puedes hacerlo, probablemente no deberías.
Dariusz
3
Dejar caer y volver a aplicar un FK está cambiando su base de datos. Estás tratando de desafiar las restricciones que permiten que el sistema tenga sentido, no tiene en cuenta que un FK podría ser algo temporal, y si lo supiera, entraría en pánico.
Grant Thomas
1
Es extraño lo que intentas hacer. ¿Pero qué base de datos estás usando?
andrefsp
44
¿Qué sucede si, en lugar de deshabilitar su restricción, la modificó permanentemente ON DELETE SET NULL? Eso lograría algo similar y no tendría que activar y desactivar la comprobación de claves.
dnagirl
1
@dnagirl: eso sería mejor, de hecho. ¿Cómo puedo hacer eso?
jul

Respuestas:

1467

Prueba DISABLE KEYSo

SET FOREIGN_KEY_CHECKS=0;

asegurate que

SET FOREIGN_KEY_CHECKS=1;

después.

Andrew Campbell
fuente
14
¿Es esto algo que está configurado para MySQL en su conjunto o solo para esa sesión?
tipu
28
Creo que es por sesión.
Andrew Campbell
13
serverfault.com/questions/291100/… , también tenga en cuenta que no puede disable keys para Innodb
Pacerier
1
¿Puedo desactivar FOREIGN_KEY_CHECKS para una sola tabla?
jDub9
@Pacerier Al leer eso, parece que puedes, pero solo para una sola sesión.
Brett
150

Para desactivar la restricción de clave externa globalmente, haga lo siguiente:

SET GLOBAL FOREIGN_KEY_CHECKS=0;

y recuerde volver a configurarlo cuando haya terminado

SET GLOBAL FOREIGN_KEY_CHECKS=1;

ADVERTENCIA: solo debe hacer esto cuando realice el mantenimiento en modo de usuario único. Como podría resultar en inconsistencia de datos. Por ejemplo, será muy útil cuando cargue una gran cantidad de datos utilizando una salida mysqldump.

berniey
fuente
1
esto es lo que necesitaba saber, así que no es una buena práctica, pero esta respuesta chicos debe ser mayor puntuación ...
ftrotter
1
Esto funcionó para mí después de intentar la 'mejor respuesta' no funcionó para mí. Quizás se podría agregar una explicación de la diferencia.
hexnet
77
@hexnet La diferencia es que solo SET FOREIGN_KEY_CHECKScambia el valor de la conexión actual , mientras que SET GLOBAL ..cambia el valor de todas las conexiones , incluidas las futuras. Si solo lo hace SET FOREIGN..en una ventana, intente aplicar la declaración en una ventana diferente (a través de una conexión diferente), el valor no ha cambiado allí. Con GLOBAL, la misma variable tiene el mismo valor para ambas conexiones.
MatsLindh
Lo único que podría ayudarme cuando reproduzco un volcado más grande (6+ GB) <3
Max
Esto no funciona para mi. Cuando lo intento, veo:ERROR 1228 (HY000): Variable 'foreign_key_checks' is a SESSION variable and can't be used with SET GLOBAL
Mike B
53

Normalmente solo deshabilito las restricciones de clave externa cuando quiero truncar una tabla, y dado que vuelvo a esta respuesta, esto es para mí en el futuro:

SET FOREIGN_KEY_CHECKS=0;
TRUNCATE TABLE table;
SET FOREIGN_KEY_CHECKS=1;
AntonioCS
fuente
25

En lugar de deshabilitar su restricción, modifíquela permanentemente a ON DELETE SET NULL. Eso logrará algo similar y no tendría que activar y desactivar la comprobación de claves. Al igual que:

ALTER TABLE tablename1 DROP FOREIGN KEY fk_name1; //get rid of current constraints
ALTER TABLE tablename2 DROP FOREIGN KEY fk_name2;

ALTER TABLE tablename1 
  ADD FOREIGN KEY (table2_id) 
        REFERENCES table2(id)
        ON DELETE SET NULL  //add back constraint

ALTER TABLE tablename2 
  ADD FOREIGN KEY (table1_id) 
        REFERENCES table1(id)
        ON DELETE SET NULL //add back other constraint

Lea esto ( http://dev.mysql.com/doc/refman/5.5/en/alter-table.html ) y esto ( http://dev.mysql.com/doc/refman/5.5/en /create-table-foreign-keys.html ).

dnagirl
fuente
77
Tenga en cuenta que la modificación de la tabla puede llevar mucho tiempo, mejor configurar el servidor global FOREIGN_KEY_CHECKSen 0 y volver a colocarlo una vez que se realiza el trabajo sucio. Además, podría bloquearse para escribir sus tablas.
Aki
¿Eso no romperá la referencia al alterar el tipo de columna remota? (Parece que mi cliente cambia el nombre de una tabla temporal modificada por el nombre de la tabla original).
Cees Timmerman
15

Para desactivar la restricción de clave externa a nivel mundial:

SET GLOBAL FOREIGN_KEY_CHECKS = 0;

y para la restricción de clave externa activa

SET GLOBAL FOREIGN_KEY_CHECKS = 1;
Umar Tariq
fuente
10

Una solución muy simple con phpmyadmin:

  • En tu tabla, ve a la SQLpestaña
  • Después de editar el comando SQL que desea ejecutar, hay una casilla de verificación al lado GO, llamada ' Habilitar comprobaciones de clave externa' .
  • Desmarca esta casilla de verificación y ejecuta tu SQL . Se volverá a verificar automáticamente después de la ejecución.
svin
fuente
3
¡Gracias! De hecho, la solución SET FOREIGN_KEY_CHECKS=0; ..... SET FOREIGN_KEY_CHECKS=1;no funcionó para mí en PHPMyAdmin porque olvidé desmarcar la casilla de verificación 'Habilitar comprobaciones de clave externa'. En PHPMyAdmin puede omitir estos comandos SET y simplemente desmarcar la casilla de verificación.
Jan
5

Para mí simplemente SET FOREIGN_KEY_CHECKS=0;no fue suficiente. Todavía estaba teniendo un com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException.

Tuve que agregar ALTER TABLE myTable DISABLE KEYS;.

Entonces:

SET FOREIGN_KEY_CHECKS=0;
ALTER TABLE myTable DISABLE KEYS;
DELETE FROM myTable;
ALTER TABLE myTable ENABLE KEYS;
SET FOREIGN_KEY_CHECKS=1;
RotS
fuente
FYI, mySQL 5.7 arroja advertencia, el motor InnoDB no tiene esta opción cuando ejecuta el comando DISABLE KEYS.
jDub9
esto funcionó, sin la tabla alternativa tampoco funcionó para mí
David Kabii
3

Si el campo clave es anulable, también puede establecer el valor en nulo antes de intentar eliminarlo:

cursor.execute("UPDATE myapp_item SET myapp_style_id = NULL WHERE n = %s", n)
transaction.commit_unless_managed() 

cursor.execute("UPDATE myapp_style SET myapp_item_id = NULL WHERE n = %s", n)
transaction.commit_unless_managed()

cursor.execute("DELETE FROM myapp_item WHERE n = %s", n)
transaction.commit_unless_managed()

cursor.execute("DELETE FROM myapp_style WHERE n = %s", n)
transaction.commit_unless_managed()
Chanoch
fuente
2

En phpMyAdmin puede seleccionar varias filas y luego hacer clic en la acción de eliminar. Ingresará a una pantalla que enumera las consultas de eliminación, puede desmarcar la verificación de Clave externa y hacer clic en Sí para ejecutarlas.

Esto le permitirá eliminar filas incluso si hay una restricción de restricción ON DELETE.

Julian
fuente
-2

No es una buena idea establecer una restricción de clave externa en 0, porque si lo hace, su base de datos no garantizaría que no esté violando la integridad referencial. Esto podría conducir a datos inexactos, engañosos o incompletos.

Usted crea una clave foránea por una razón: porque todos los valores en la columna secundaria serán los mismos que los valores en la columna primaria. Si no hay restricciones de clave externa, una fila secundaria puede tener un valor que no está en la fila principal, lo que conduciría a datos inexactos.

Por ejemplo, supongamos que tiene un sitio web para que los estudiantes inicien sesión y todos los estudiantes deben registrarse para obtener una cuenta como usuario. Tiene una tabla para identificadores de usuario, con ID de usuario como clave principal; y otra tabla para cuentas de estudiantes, con la identificación del estudiante como columna. Dado que cada estudiante debe tener una identificación de usuario, tendría sentido hacer que la identificación de estudiante de la tabla de cuentas de estudiantes sea una clave externa que haga referencia a la identificación de usuario de la clave principal en la tabla de ID de usuario. Si no hay comprobaciones de claves externas, un estudiante podría terminar teniendo una identificación de estudiante y ninguna identificación de usuario, lo que significa que un estudiante puede obtener una cuenta sin ser un usuario, lo cual está mal.

Imagínese si le sucede a una gran cantidad de datos. Es por eso que necesita la verificación de clave externa.

Es mejor averiguar qué está causando el error. Lo más probable es que esté intentando eliminar de una fila principal sin eliminar de una fila secundaria. Intente eliminar de la fila secundaria antes de eliminar de la fila primaria.

Valencia Starr
fuente
Es cierto, siempre hay una compensación.
Pacerier
21
Nadie dice que lo ejecute así para siempre. Desactiva las restricciones, carga en masa algunos datos y los vuelve a activar. No es gran cosa, la gente lo hace todo el tiempo.
bwawok
Es necesario para las importaciones a granel, por lo menos para el rendimiento, es muy común. También a veces solo necesita restaurar los datos, luego puede hacer sus comprobaciones.
Firas Abd Alrahman
3
Esta no es una respuesta a la pregunta.
Koray Tugay
Tenga en cuenta que su pregunta es cómo hacer esto temporalmente. Esto se requiere cuando se realizan ciertas importaciones de mantenimiento y datos. La advertencia, por supuesto, es que sus scripts de importación se vuelven responsables de la integridad de los datos. Luego, más tarde, cuando los índices y las restricciones se vuelvan a activar, la base de datos le dirá si algo está roto.
mcstar