8

Tôi có hai bảng đã tồn tại mà trông (một phần) gần như thế này:Thay đổi MySQL khóa chính khi contraints chính nước ngoài tồn tại

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; 

Tôi muốn thêm một auto-incrementing số nguyên mới id cột để parent và sử dụng nó làm khóa chính thay vào đó, trong khi vẫn giữ old_pk làm khóa duy nhất và cho phép các bảng khác như child tham chiếu nó trong các ràng buộc khóa ngoài. Thật không may, chỉ cần nói ALTER TABLE parent DROP PRIMARY KEY không hoạt động:

Error Code: 1025

Lỗi trên đổi tên của './data/#sql-4013_70f5e' thành './data/parent' (errno: 150)

Một số googling cho thấy điều này là do tham chiếu khóa ngoài hiện có từ child. Về bản chất, tôi cần một cách để nói với MySQL "sử dụng cột khác này làm khóa chính, nhưng đừng quên khóa-duy nhất của bản gốc". Có cách nào để thực hiện điều này, khác hơn là chỉ thả các ràng buộc chính từ child và phục hồi chúng sau đó?

Giả sử rằng tôi phải thay đổi các bảng tại chỗ, thay vì tạo bản sao có cùng dữ liệu và hoán đổi chúng sau này. Tôi đã thử sử dụng SET FOREIGN_KEY_CHECKS = 0 trước khi thay đổi bảng, nhưng nó dường như không giúp đỡ.

+0

đó là lý do tại sao tôi không làm khóa chính người dùng có thể nhìn thấy (tôi là tất cả đối với khóa chính thay thế từ get-go), yêu cầu thay đổi người dùng là một nhức đầu, nhưng thật tuyệt khi biết bạn đang tạo cơ sở dữ liệu của mình sử dụng khóa chính thay thế chính http://en.wikipedia.org/wiki/Surrogate_key –

Trả lời

7

Thêm một chỉ số (thậm chí nó có thể là UNIQUE) để old_pk trước khi thả các khóa chính:

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

Hoàn toàn không hiệu quả với tôi. –

-7

Tôi sẽ cân nhắc điều này với những gì có thể là đề xuất không được ưa chuộng. Không sử dụng các ràng buộc khóa ngoài trong cơ sở dữ liệu của bạn - thực thi khóa duy nhất và các ràng buộc khác thông qua TSQL trong các thủ tục được lưu trữ khi cần thiết. Đó là kinh nghiệm của tôi rằng trong môi trường thu nhỏ kiểm tra các ràng buộc hiếm khi được sử dụng.

Tôi nói điều này với ý thức cởi mở để phản đối các nhận xét/thảo luận có thể xảy ra. Tôi không nói rằng đề xuất này là chính xác, chỉ là nó đã được các ý kiến ​​hiện hành trong các cửa hàng tôi đã làm việc tại.

Yêu cầu: Nếu bạn downvote tôi, xin vui lòng để lại một bình luận ngắn là tốt. Trong 10 năm hoặc lâu hơn, tôi đã làm việc với các cơ sở dữ liệu quan hệ, những người duy nhất tôi biết sử dụng các ràng buộc kiểm tra đang làm việc trên các hệ thống không ở quy mô lớn. Nếu đó là những người downvoting tôi thì tôi có thể sống với điều đó. Nhưng nếu bạn đang làm việc trên một hệ thống thu nhỏ và kiểm tra ràng buộc là tiêu chuẩn cho bạn tôi muốn biết bạn là ai để tôi có thể làm một số đọc để xem những gì tôi đã bỏ lỡ.

+0

"ở quy mô [tối đa] ! = thực tiễn tốt nhất. – ProfileTwist

Các vấn đề liên quan