Pregunta

Estoy usando MySQL y tengo una tabla con un índice que se usa como clave externa en muchas otras tablas. Quiero cambiar el tipo de datos del índice (de entero con signo a sin signo), ¿cuál es la mejor manera de hacerlo?

Intenté alterar el tipo de datos en el campo de índice, pero eso falla porque se está utilizando como una clave externa para otras tablas. Intenté alterar el tipo de datos en una de las claves externas, pero eso falló porque no coincidía con el tipo de datos del índice.

Supongo que podría eliminar manualmente todas las restricciones de clave externa, cambiar los tipos de datos y agregar las restricciones, pero esto sería mucho trabajo porque tengo muchas tablas que usan este índice como clave externa. ¿Hay alguna manera de desactivar temporalmente las restricciones de clave externa mientras se realiza un cambio? Además, ¿hay alguna manera de obtener una lista de todos los campos que hacen referencia al índice como una clave externa?

Actualización: Intenté modificar la clave externa después de desactivar las comprobaciones de clave externa, pero no parece estar desactivando las comprobaciones:

SET foreign_key_checks = 0;

ALTER TABLE `escolaterrafir`.`t23_aluno` MODIFY COLUMN `a21_saida_id` INTEGER DEFAULT NULL;

Aquí está el error:

------------------------
LATEST FOREIGN KEY ERROR
------------------------
090506 11:57:34 Error in foreign key constraint of table escolaterrafir/t23_aluno:
there is no index in the table which would contain
the columns as the first columns, or the data types in the
table do not match to the ones in the referenced table
or one of the ON ... SET NULL columns is declared NOT NULL. Constraint:
,
  CONSTRAINT FK_t23_aluno_8 FOREIGN KEY (a21_saida_id) REFERENCES t21_turma (A21_ID)

Definición de la tabla de índice:

DROP TABLE IF EXISTS `escolaterrafir`.`t21_turma`;
CREATE TABLE  `escolaterrafir`.`t21_turma` (
  `A21_ID` int(10) unsigned NOT NULL auto_increment,
  ...
) ENGINE=InnoDB AUTO_INCREMENT=51 DEFAULT CHARSET=latin1;

y la tabla que tiene la clave externa que apunta a ella:

DROP TABLE IF EXISTS `escolaterrafir`.`t23_aluno`;
CREATE TABLE  `escolaterrafir`.`t23_aluno` (
  ...
  `a21_saida_id` int(10) unsigned default NULL,
  ...
  KEY `Index_7` (`a23_id_pedagogica`),
  ...
  CONSTRAINT `FK_t23_aluno_8` FOREIGN KEY (`a21_saida_id`) REFERENCES `t21_turma` (`A21_ID`)
) ENGINE=InnoDB AUTO_INCREMENT=387 DEFAULT CHARSET=latin1;
¿Fue útil?

Solución 2

Para responder a mi propia pregunta, no pude descubrir una forma más sencilla de hacerlo. Terminé eliminando todas las restricciones de clave externa, cambiando los tipos de campo y luego agregando todas las restricciones de clave externa.

Como señaló R. Bemrose, usar SET foreign_key_checks = 0; solo ayuda al agregar o cambiar datos, pero no permite comandos ALTER TABLE que romperían la clave foránea restricciones.

Otros consejos

Aquí está mi pequeña contribución a este hilo. ¡Gracias a Daniel Schneller por la inspiración y por darme una gran parte de la solución!

set group_concat_max_len = 2048;
set @table_name = "YourTableName";
set @change = "bigint unsigned";
select distinct table_name,
       column_name,
       constraint_name,
       referenced_table_name,
       referenced_column_name,
       CONCAT(
           GROUP_CONCAT('ALTER TABLE ',table_name,' DROP FOREIGN KEY ',constraint_name SEPARATOR ';'),
           ';',
           GROUP_CONCAT('ALTER TABLE `',table_name,'` CHANGE `',column_name,'` `',column_name,'` ',@change SEPARATOR ';'),
           ';',
           CONCAT('ALTER TABLE `',@table_name,'` CHANGE `',referenced_column_name,'` `',referenced_column_name,'` ',@change),
           ';',
           GROUP_CONCAT('ALTER TABLE `',table_name,'` ADD CONSTRAINT `',constraint_name,'` FOREIGN KEY(',column_name,') REFERENCES ',referenced_table_name,'(',referenced_column_name,')' SEPARATOR ';')
       ) as query
from   INFORMATION_SCHEMA.key_column_usage
where  referenced_table_name is not null
   and referenced_column_name is not null
   and referenced_table_name = @table_name
group by referenced_table_name

Al configurar @table_name y @change puede generar una consulta. @table_name debe ser el nombre de la tabla con la clave principal (buscará las tablas que usan esa columna como clave externa) y cambiará su tipo a @change.

Tuve que cambiar algunas tablas así, así que funcionó de maravilla. Solo tuve que cambiar @table_name y luego realizar una consulta.

Para obtener información sobre el uso de restricciones de clave externa, emita la siguiente consulta en la base de datos INFORMATION_SCHEMA :

select distinct table_name, 
       column_name, 
       constraint_name,  
       referenced_table_name, 
       referenced_column_name 
from   key_column_usage 
where  constraint_schema = 'XXX' 
   and referenced_table_name is not null 
   and referenced_column_name is not null;

Reemplace XXX con su nombre de esquema. Esto le dará una lista de tablas y columnas que se refieren a otras columnas como claves foráneas.

Desafortunadamente, los cambios en el esquema no son transaccionales, por lo que temo que de hecho tengas que deshabilitar temporalmente las llaves_extranjeras para esta operación. Recomiendo, si es posible, evitar conexiones de cualquier cliente durante esta fase para minimizar el riesgo de violaciones accidentales de restricciones.

En cuanto a las claves en sí: también deberán eliminarse y recrearse cuando haya cambiado los tipos de datos de la tabla.

Puede deshabilitar temporalmente las claves foráneas escribiendo

SET foreign_key_checks = 0;

y para volver a habilitarlos

SET foreign_key_checks = 1;

Creo que esto requiere privilegios de administrador, porque está destinado a importar datos en la base de datos.

Editar : en reacción a su edición, parece que solo deshabilita las restricciones para las declaraciones DML (insertar, actualizar, eliminar) pero no las declaraciones DDL (alterar tabla, descartar tabla, etc.) ).

Si puede detener la base de datos, intente volcar las tablas en un archivo de texto, cambie la definición de las columnas manualmente en el archivo e importe las tablas nuevamente.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top