我有两个已经存在的表,看起来(部分)大致如下:
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
的现有外键引用引起的。从本质上讲,我需要一种方法来告诉MySQL“使用其他列作为主键,但不要忘记原始列的唯一键 - ”。有没有办法实现这一点,除了从child
删除关键约束并在之后恢复它们?
假设我必须在适当的位置更改表,而不是使用相同的数据创建副本并在以后交换它们。我在更改表之前尝试使用SET FOREIGN_KEY_CHECKS = 0
,但似乎没有用。
答案 0 :(得分:7)
在删除主键之前,将一个索引(甚至可能是UNIQUE)添加到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)
答案 1 :(得分:-6)
我会对这个可能不受欢迎的建议进行权衡。不要在数据库中使用外键约束 - 根据需要通过TSQL在存储过程中强制执行唯一键和其他约束。根据我的经验,在规模化的环境中,很少使用检查约束。
我以开放的心态说出反对可能随之发表的评论/讨论。我并不是说这个建议是正确的,只是在我工作的商店里一直是流行的观点。
请求:如果您向我发送信息,请同时发表简短评论。在大约10年左右的时间里,我一直在使用关系数据库,我认识的唯一使用检查约束的人正在研究那些规模不大的系统。如果那些是那些低估我的人,那么我就可以忍受。但是如果你正在研究一个缩放系统并检查约束是否适合你,我想知道你是谁,所以我可以做一些阅读,看看我错过了什么。