2009-05-06 17 views
10

Estoy usando MySQL y tengo una tabla con un índice que se usa como clave foránea en muchas otras tablas. Quiero cambiar el tipo de datos del índice (desde el número de registro al entero sin signo), ¿cuál es la mejor manera de hacerlo?MySQL change type of foreign key

He intentado modificar el tipo de datos en el campo de índice, pero eso falla porque se está utilizando como una clave externa para otras tablas. Traté de 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 forma de desactivar temporalmente las restricciones de clave externa mientras se realiza un cambio? Además, ¿hay alguna forma 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 apagar revisión de las llaves extranjeras, pero no parece ser apagar los controles:

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 la misma:

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; 

Respuesta

8

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

Como observó R. Bemrose, usar SET foreign_key_checks = 0; solo ayuda al agregar o cambiar datos, pero no permite los comandos ALTER TABLE que rompen las restricciones de clave externa.

+4

Tuve el mismo problema, para resolverlo I: mysqldump'ed la base de datos a un archivo de texto, cambió las columnas en cuestión y volvió a importarlo. Creo que esa es la forma más fácil/rápida. – Pedru

1

Puede desactivar las claves externas temporalmente escribiendo

SET foreign_key_checks = 0; 

y para volver a activar los

SET foreign_key_checks = 1; 

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

Editar: Como reacción a su edición, parece que sólo se desactiva restricciones para las sentencias DML (insertar, actualizar, eliminar), pero no las instrucciones de DDL (alter table, la caída de mesa, etc ...).

1

para averiguar sobre el uso de claves foráneas, emitir 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; 

Reemplazar XXX con su nombre de esquema. Esto le dará una lista de tablas y columnas que hacen referencia a otras columnas como claves foráneas.

Lamentablemente, los cambios de esquema no son transaccionales, así que me temo que tendrá que desactivar temporalmente las claves de clave extranjeras para esta operación. Recomiendo, si es posible, evitar conexiones de clientes durante esta fase para minimizar el riesgo de violaciones accidentales de restricciones.

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

1

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

6

Aquí está mi pequeña contribución a este hilo. ¡Gracias a Daniel Schneller por su 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 `id` `id` ',@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 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 un nombre de tabla de la tabla con la clave principal (buscará las tablas que usan esa columna como una clave externa) y cambiará su tipo a @change.

Tuve que cambiar unas pocas mesas así, así que funcionó como un amuleto. Solo tuve que cambiar @table_name y luego realizar una consulta.

+0

Debe mencionar que está utilizando la base de datos 'INFORMATION_SCHEMA', que contiene las definiciones de todas las bases de datos regulares, para realizar estos cambios. Creo que también debería agregar 'y TABLE_SCHEMA = my_database_name' a la cláusula where, de lo contrario su consulta afectará las tablas del mismo nombre en todas las bases de datos, donde" my_database_name "sería el nombre de la base de datos donde reside su tabla. –

+0

Anexando a mi comentario anterior, quizás 'CONSTRAINT_SCHEMA' en lugar de' TABLE_SCHEMA' es lo que necesita hacer ?? –

+0

Tuve que reemplazar: 'CONCAT ('ALTER TABLE \'', @ table_name, '\ 'CHANGE \' id \ '\' id \ '', @ change),' to 'CONCAT ('ALTER TABLE \'', @table_name, '\ 'CHANGE \'', column_name, '\ '\'', column_name, '\ '', @ change),' y 'from key_column_usage' a' from INFORMATION_SCHEMA.KEY_COLUMN_USAGE' –

Cuestiones relacionadas