¿Cómo cambiar la acción referencial de clave externa? (comportamiento)

102

He configurado una tabla que contiene una columna con una clave externa, configurada en ON DELETE CASCADE(eliminar el hijo cuando se elimina el padre)

¿Cuál sería el comando SQL para cambiar esto ON DELETE RESTRICT? (no se puede borrar el padre si tiene hijos)

Moak
fuente

Respuestas:

170

Pregunta anterior pero agregando respuesta para que uno pueda obtener ayuda

Su proceso de dos pasos:

Supongamos que a table1tiene una clave externa con nombre de columna fk_table2_id, con nombre de restricciónfk_name y table2se refiere a una tabla con clave t2( algo como a continuación en mi diagrama ).

   table1 [ fk_table2_id ] --> table2 [t2]

Primer paso , ELIMINAR la vieja RESTRICCIÓN: ( referencia )

ALTER TABLE `table1` 
DROP FOREIGN KEY `fk_name`;  

aviso de restricción se elimina, la columna no se elimina

Segundo paso , AGREGUE una nueva RESTRICCIÓN:

ALTER TABLE `table1`  
ADD CONSTRAINT `fk_name` 
    FOREIGN KEY (`fk_table2_id`) REFERENCES `table2` (`t2`) ON DELETE CASCADE;  

agregando restricción, la columna ya está allí

Ejemplo:

Tengo una UserDetailstabla se refiere a la Userstabla:

mysql> SHOW CREATE TABLE UserDetails;
:
:
 `User_id` int(11) DEFAULT NULL,
  PRIMARY KEY (`Detail_id`),
  KEY `FK_User_id` (`User_id`),
  CONSTRAINT `FK_User_id` FOREIGN KEY (`User_id`) REFERENCES `Users` (`User_id`)
:
:

Primer paso:

mysql> ALTER TABLE `UserDetails` DROP FOREIGN KEY `FK_User_id`;
Query OK, 1 row affected (0.07 sec)  

Segundo paso:

mysql> ALTER TABLE `UserDetails` ADD CONSTRAINT `FK_User_id` 
    -> FOREIGN KEY (`User_id`) REFERENCES `Users` (`User_id`) ON DELETE CASCADE;
Query OK, 1 row affected (0.02 sec)  

resultado:

mysql> SHOW CREATE TABLE UserDetails;
:
:
`User_id` int(11) DEFAULT NULL,
  PRIMARY KEY (`Detail_id`),
  KEY `FK_User_id` (`User_id`),
  CONSTRAINT `FK_User_id` FOREIGN KEY (`User_id`) REFERENCES 
                                       `Users` (`User_id`) ON DELETE CASCADE
:
Grijesh Chauhan
fuente
2
¿No debería la restricción que agregue ser ON DELETE RESTRICT como lo solicita la pregunta original?
Noumenon
Ehm, ¿qué es "en cascada de borrado" y por qué es necesario?
Lealo
3
@Noumenon RESTRICT es el valor predeterminado, por lo que se obtiene cuando no se especifica.
edruid
1
@Lealo "en cascada de eliminación" significa que si elimina una fila de la tabla principal (Usuarios en este caso), todas las filas de referencia de la tabla secundaria (UserDetails) también se eliminan.
edruid
1
gracias por las notas "se eliminó la restricción de aviso, la columna no se eliminó", "se agregó restricción, la columna ya está allí", supongo que eso significa que los datos se conservan prácticamente y solo el esquema cambia allí
George Birbilis
21

Puede hacer esto en una consulta si está dispuesto a cambiar su nombre:

ALTER TABLE table_name
  DROP FOREIGN KEY `fk_name`,
  ADD CONSTRAINT `fk_name2` FOREIGN KEY (`remote_id`)
    REFERENCES `other_table` (`id`)
    ON DELETE CASCADE;

Esto es útil para minimizar el tiempo de inactividad si tiene una mesa grande.

Romuald Brunet
fuente
12
ALTER TABLE DROP FOREIGN KEY fk_name;
ALTER TABLE ADD FOREIGN KEY fk_name(fk_cols)
            REFERENCES tbl_name(pk_names) ON DELETE RESTRICT;
pascal
fuente
2
me ayudó a encontrar la solución ALTER TABLE table_name ADD...ON DELETE RESTRICT
Moak
3
No, fk_name es el nombre de la restricción. Es opcional proporcionar uno. No estoy seguro, pero tal vez puedas recuperarlo usando SHOW CREATE TABLE.
pascal
1
ON CASCADE RESTRICT probablemente no sea su intención.
jgreep
5

Recuerde que MySQL mantiene un índice simple en una columna después de eliminar la clave externa. Entonces, si necesita cambiar la columna 'referencias', debe hacerlo en 3 pasos

  • soltar FK original
  • soltar un índice (nombres como fk anterior, drop indexcláusula de uso )
  • crear nuevo FK
Vasiliy
fuente
3

Simplemente puede usar una consulta para gobernarlos a todos: ALTER TABLE products DROP FOREIGN KEY oldConstraintName, ADD FOREIGN KEY (product_id, category_id) REFERENCES externalTableName (foreign_key_name, another_one_makes_composite_key) ON DELETE CASCADE ON UPDATE CASCADE

stamster
fuente
1
esto funcionará solo si cambia el nombre de la restricción (si usa un nombre generado automáticamente, probablemente funcionará, supongo que MySQL siempre crea
nombres
La consulta funciona con seguridad en MySQL / MariaDB. La clave aquí es eliminar la restricción anterior por su nombre, que se está haciendo en la línea 2.
Stamster
1
La sintaxis de consulta todo en uno no me funcionó con MySQL cuando se usaron nombres de restricciones explícitas
George Birbilis
3

Tenía que modificar un montón de FK, así que escribí algo para hacer las declaraciones por mí. Pensé que compartiría:

SELECT

CONCAT('ALTER TABLE `' ,rc.TABLE_NAME,
    '` DROP FOREIGN KEY `' ,rc.CONSTRAINT_NAME,'`;')
, CONCAT('ALTER TABLE `' ,rc.TABLE_NAME,
    '` ADD CONSTRAINT `' ,rc.CONSTRAINT_NAME ,'` FOREIGN KEY (`',kcu.COLUMN_NAME,
    '`) REFERENCES `',kcu.REFERENCED_TABLE_NAME,'` (`',kcu.REFERENCED_COLUMN_NAME,'`) ON DELETE CASCADE;')

FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS rc
LEFT OUTER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE kcu
    ON kcu.TABLE_SCHEMA = rc.CONSTRAINT_SCHEMA
    AND kcu.CONSTRAINT_NAME = rc.CONSTRAINT_NAME
WHERE DELETE_RULE = 'NO ACTION'
AND rc.CONSTRAINT_SCHEMA = 'foo'
DavidSM
fuente
1
esto no funcionará si una restricción está en varias columnas. el sql generado creará restricciones separadas para cada columna
enciende el
Todos mis FK estaban en columnas individuales, por lo que no estaba pensando tanto en esa posibilidad, pero buen pensamiento
DavidSM