8

Tengo dos tablas ya existentes que se ven (en parte) más o menos así:Cambio de clave principal de MySQL cuando existe contraints clave externa

CREATE TABLE parent (
    old_pk CHAR(8) NOT NULL PRIMARY KEY 
) ENGINE=InnoDB; 

CREATE TABLE child (
    parent_key CHAR(8), 
    FOREIGN KEY (parent_key) REFERENCES parent(old_pk) 
     ON UPDATE CASCADE ON DELETE CASCADE 
) ENGINE=InnoDB; 

Quiero añadir un nuevo número entero de incremento automático id columna para parent y utilizarlo como la clave principal en su lugar, si bien mantienen old_pk como clave única y permitiendo que otras tablas como child hacer referencia a ella en contraints clave externa. Por desgracia, simplemente diciendo ALTER TABLE parent DROP PRIMARY KEY no funciona:

Código de error: 1025

error de cambiar el nombre de './data/#sql-4013_70f5e' a './data/parent' (Error: 150)

algunas google sugiere que esto se debe a la referencia de clave externa existente de child. En esencia, necesito una forma de decirle a MySQL "use esta otra columna como clave principal, pero no olvide la clave única del original". ¿Hay alguna manera de lograr esto, que no sea simplemente eliminar las restricciones clave del child y restablecerlas después?

Supongamos que debo modificar las tablas en su lugar, en lugar de crear copias con los mismos datos y cambiarlos más tarde. Intenté usar SET FOREIGN_KEY_CHECKS = 0 antes de modificar la tabla, pero parece que no me ayuda.

+0

Es por eso que no hago clave primaria visible para el usuario (Estoy a favor de clave primaria sustituta de el primer momento), los requisitos cambiantes de los usuarios son un dolor de cabeza, pero es bueno saber que está haciendo uso de su base de datos sustituta clave principal http://en.wikipedia.org/wiki/Surrogate_key –

Respuesta

7

Añadir un índice (incluso podría ser únicas) a old_pk antes de caer la clave principal:

mysql> CREATE TABLE parent (
    ->  old_pk CHAR(8) NOT NULL PRIMARY KEY 
    ->) ENGINE=InnoDB; 
Query OK, 0 rows affected (0.00 sec) 

mysql> CREATE TABLE child (
    ->  parent_key CHAR(8), 
    ->  FOREIGN KEY (parent_key) REFERENCES parent(old_pk) 
    ->   ON UPDATE CASCADE ON DELETE CASCADE 
    ->) ENGINE=InnoDB; 
Query OK, 0 rows affected (0.00 sec) 

mysql> INSERT INTO parent VALUES ('a'); 
Query OK, 1 row affected (0.01 sec) 

mysql> CREATE INDEX old_pk_unique ON parent (old_pk); 
Query OK, 1 row affected (0.01 sec) 
Records: 1 Duplicates: 0 Warnings: 0 

mysql> ALTER TABLE parent DROP PRIMARY KEY; 
Query OK, 1 row affected (0.01 sec) 
Records: 1 Duplicates: 0 Warnings: 0 

mysql> INSERT INTO child VALUES ('a'); 
Query OK, 1 row affected (0.00 sec) 

mysql> SHOW CREATE TABLE parent; 
+--------+------------------------------------------------------------------------------------------------------------------------------+ 
| Table | Create Table                             | 
+--------+------------------------------------------------------------------------------------------------------------------------------+ 
| parent | CREATE TABLE `parent` (
    `old_pk` char(8) NOT NULL, 
    KEY `old_pk_unique` (`old_pk`) 
) ENGINE=InnoDB DEFAULT CHARSET=latin1 | 
+--------+------------------------------------------------------------------------------------------------------------------------------+ 
1 row in set (0.00 sec) 

mysql> INSERT INTO child VALUES ('b'); 
ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (`test/child`, CONSTRAINT `child_ibfk_1` FOREIGN KEY (`parent_key`) REFERENCES `parent` (`old_pk`) ON DELETE CASCADE ON UPDATE CASCADE) 

mysql> INSERT INTO parent VALUES ('b'); 
Query OK, 1 row affected (0.00 sec) 

mysql> INSERT INTO child VALUES ('b'); 
Query OK, 1 row affected (0.01 sec) 

mysql> ALTER TABLE parent ADD id INT; 
Query OK, 2 rows affected (0.00 sec) 
Records: 2 Duplicates: 0 Warnings: 0 

mysql> UPDATE parent SET id = 1 WHERE old_pk = 'a'; 
Query OK, 1 row affected (0.01 sec) 
Rows matched: 1 Changed: 1 Warnings: 0 

mysql> UPDATE parent SET id = 2 WHERE old_pk = 'b'; 
Query OK, 1 row affected (0.00 sec) 
Rows matched: 1 Changed: 1 Warnings: 0 

mysql> ALTER TABLE parent ADD PRIMARY KEY (id); 
Query OK, 2 rows affected (0.00 sec) 
Records: 2 Duplicates: 0 Warnings: 0 

mysql> SHOW CREATE TABLE parent; 
+--------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ 
| Table | Create Table                                            | 
+--------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ 
| parent | CREATE TABLE `parent` (
    `old_pk` char(8) NOT NULL, 
    `id` int(11) NOT NULL default '0', 
    PRIMARY KEY (`id`), 
    KEY `old_pk_unique` (`old_pk`) 
) ENGINE=InnoDB DEFAULT CHARSET=latin1 | 
+--------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ 
1 row in set (0.00 sec) 
+0

No funciona en absoluto para mí. –

-7

Voy a opinar sobre esto con lo que puede ser una sugerencia impopular. No utilice restricciones de clave externa en su base de datos: haga cumplir clave única y otras restricciones mediante TSQL en procedimientos almacenados según sea necesario. Según mi experiencia, en entornos a escala las restricciones de comprobación rara vez se usan.

Digo esto con la mente abierta a los comentarios/discusiones opuestos que puedan surgir. No estoy diciendo que esta sugerencia es correcta, sólo que ha sido la opinión que prevalece en las tiendas He trabajado en

Una solicitud:. Si me Downvote, también deje por favor un breve comentario también. En los 10 años que llevo trabajando con bases de datos relacionales, las únicas personas que conozco que usan restricciones de verificación trabajan en sistemas que no son a escala. Si esas son las personas que me vengan abajo, entonces puedo vivir con eso. Pero si está trabajando en un sistema a escala y las restricciones de verificación son la norma para usted, me gustaría saber quién es usted, así que puedo leer un poco para ver lo que me he perdido.

+0

"en [max] escala" prácticas ! = mejores prácticas. – ProfileTwist

Cuestiones relacionadas