8

Mam dwóch już istniejących tabel, które wyglądają (częściowo) z grubsza tak:Zmiana MySQL klucz podstawowy, gdy istnieje klucz obcy contraints

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; 

Chcę dodać nową autoinkrementacja liczbą całkowitą id kolumnę parent i użyj go jako klucza podstawowego, zachowując jednocześnie old_pk jako unikalny klucz i zezwalając innym tabelom takim jak child na odwoływanie się do nich w ograniczeniach klucza obcego. Niestety, po prostu mówiąc ALTER TABLE parent DROP PRIMARY KEY nie działa:

Kod błędu: 1025

Błąd na zmiany nazwy z './data/#sql-4013_70f5e' do './data/parent' (errno: 150)

Niektóre metody googlowania sugerują, że jest to spowodowane istniejącym kluczem obcy z numerem child. W istocie, potrzebuję sposobu, aby powiedzieć MySQL "użyj tej drugiej kolumny jako klucza podstawowego, ale nie zapomnij o unikalnym kluczu oryginalnego". Czy jest jakiś sposób, aby to osiągnąć, poza porzuceniem kluczowych ograniczeń z child i przywróceniem ich później?

Załóżmy, że muszę zmienić tabele w miejscu, zamiast tworzyć kopie z tymi samymi danymi i zamienić je później. Próbowałem używać SET FOREIGN_KEY_CHECKS = 0 przed zmianą tabeli, ale to nie pomaga.

+0

Dlatego nie rób klucz podstawowy widoczne dla użytkownika (Jestem za surogat klucza podstawowego z the-get), zmieniające wymagania użytkownika to ból głowy, ale dobrze jest wiedzieć, że twoja baza danych używa zastępczego klucza głównego http://en.wikipedia.org/wiki/Surrogate_key –

Odpowiedz

7

Dodaj indeks (może to nawet być unikalny) do old_pk przed zrzuceniem klucz podstawowy:

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

Nie działa dla mnie. –

-7

Będę ważyć to, co może być niepopularną sugestią. Nie używaj ograniczeń klucza obcego w bazie danych - w razie potrzeby wymuszaj unikalny klucz i inne ograniczenia za pośrednictwem TSQL w procedurach przechowywanych. Z mojego doświadczenia wynika, że ​​ograniczenia skalowania rzadko są używane w skalowanych środowiskach.

Mówię to z otwartym umysłem na przeciwstawne komentarze/dyskusje, które mogą się pojawić. Nie twierdzę, że ta sugestia jest poprawna, tylko że była to powszechna opinia w sklepach, w których pracowałem.

Wniosek: Jeśli zarzuciłeś mi, proszę również zostawić krótki komentarz. Przez około 10 lat pracowałem z relacyjnymi bazami danych, a jedyni ludzie, którzy znają ograniczenia kontroli, pracują nad systemami, które nie są na wielką skalę. Jeśli to ludzie mnie spowalniają, to mogę z tym żyć. Ale jeśli pracujesz nad skalowanym systemem i sprawdzasz, czy ograniczenia są dla ciebie normą, chciałbym wiedzieć, kim jesteś, więc mogę przeczytać, żeby zobaczyć, co przeoczyłem.

+0

"w [max] skali" praktyk ! = najlepsze praktyki. – ProfileTwist