8

我有看(部分)兩個已存在的表大致是這樣的:修改MySQL的主鍵時,外鍵約束上存在

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; 

我想id列添加到parent一個新的自動遞增的整數並將其用作主鍵代替,同時仍將old_pk作爲唯一鍵並允許其他表(如child)在外鍵約束中引用它。不幸的是,簡單地說ALTER TABLE parent DROP PRIMARY KEY不起作用:

錯誤代碼:1025

上 './data/#sql-4013_70f5e' 到 './data/parent'(錯誤的命名錯誤:150 )

一些使用谷歌搜索建議這是由於從child現有的外鍵參考。實質上,我需要一種方法告訴M​​ySQL「使用這個其他列作爲主鍵,但不要忘記原始鍵的唯一鍵」。除了從child中刪除關鍵限制並在之後恢復它們之外,有什麼方法可以實現這一點嗎?

假設我必須改變表格的位置,而不是使用相同的數據創建副本並在以後交換它們。在嘗試更改表格之前,我嘗試過使用SET FOREIGN_KEY_CHECKS = 0,但似乎沒有幫助。

+0

,這就是爲什麼我不作用戶可見的主鍵(我所有的從代理主鍵用戶不斷變化的需求是一件令人頭痛的事情,但很高興知道您正在使用代理主鍵http://en.wikipedia.org/wiki/Surrogate_key – 2009-08-05 06:43:39

回答

7

添加一個索引(甚至可能是唯一的)下降的主鍵之前old_pk:

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

根本不適用於我。 – 2012-12-07 21:28:38

-7

我會考慮這可能是一個不受歡迎的建議。不要在數據庫中使用外鍵約束 - 根據需要在存儲過程中通過TSQL強制執行唯一鍵和其他約束。根據我的經驗,在縮放環境中,很少使用檢查約束。

我以開放的態度對此表示反對可能發生的評論/討論。我並不是說這個建議是正確的,只是它一直是我工作過的商店中普遍的觀點。

A要求:如果你冷落我,也請留下一個簡短的評論。在10年左右的時間裏,我一直在處理關係數據庫,我所知道的唯一使用檢查約束的人員正在研究不規模的系統。如果這些人是低調的我,那麼我可以忍受。但是如果你在一個縮放系統上工作,並檢查約束是你的常態,我想知道你是誰,所以我可以做一些閱讀,看看我錯過了什麼。

+0

「在最大規模」實踐中!=最佳做法。 – ProfileTwist 2016-08-25 02:23:27