8

Ho due tavoli già esistenti che sembrano (in parte) più o meno in questo modo:Modifica chiave primaria MySQL quando vincoli di chiave esterna esiste

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; 

voglio aggiungere un nuovo intero incremento automatico id colonna parent e usarlo invece come chiave primaria, mantenendo allo stesso tempo old_pk come chiave univoca e consentendo ad altre tabelle come child di fare riferimento a contorni di chiave esterna. Purtroppo, semplicemente dicendo ALTER TABLE parent DROP PRIMARY KEY non funziona:

Codice errore: 1025

Errore ridenominazione del './data/#sql-4013_70f5e' a './data/parent' (errno: 150

Alcuni googling suggeriscono che ciò è dovuto al riferimento di chiave esterna esistente da child. In sostanza, ho bisogno di un modo per dire a MySQL "usa questa altra colonna come chiave primaria, ma non dimenticare la chiave univoca di quella originale". C'è un modo per farlo, oltre a eliminare i vincoli principali da child e ripristinarli in seguito?

Si supponga di dover modificare le tabelle in luogo, anziché creare copie con gli stessi dati e scambiarle successivamente. Ho provato a utilizzare SET FOREIGN_KEY_CHECKS = 0 prima di modificare la tabella, ma non sembra essere di aiuto.

+0

è per questo che non faccio chiave primaria visibile all'utente (Sono tutti per chiave primaria surrogata da il go-go), i requisiti di modifica dell'utente sono un mal di testa, ma è bene sapere che stai facendo in modo che il tuo database usi la chiave primaria sostitutiva http://en.wikipedia.org/wiki/Surrogate_key –

risposta

7

Aggiungere un indice (che potrebbe anche essere unico) per old_pk prima di cadere la chiave primaria:

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

Non funziona affatto per me. –

-7

Mi occuperò di questo con quello che potrebbe essere un suggerimento impopolare. Non utilizzare vincoli di chiave esterna nel database: applica la chiave univoca e altri vincoli tramite TSQL nelle stored procedure secondo necessità. È la mia esperienza che in ambienti scalati i vincoli di controllo vengono usati raramente.

Dico questo con una mente aperta ai commenti/discussioni avversari che possono derivarne. Non sto dicendo che questo suggerimento è corretta, solo che è stato il parere prevalente nei negozi che ho lavorato in

una richiesta:. Se mi downvote, si prega di lasciare anche un commento breve pure. Negli ultimi 10 anni ho lavorato con database relazionali, le uniche persone che conosco che usano i vincoli di controllo stanno lavorando su sistemi che non sono in scala. Se quelle sono le persone che mi hanno fatto downvoting, allora posso conviverci. Ma se stai lavorando su un sistema in scala e controlli i vincoli sono la norma per te vorrei sapere chi sei così posso fare un po 'di lettura per vedere cosa ho perso.

+0

"alla scala [max]" ! = migliori pratiche. – ProfileTwist

Problemi correlati