8

私は(部分的に)大まかに次のように見える2つの既存のテーブルを持っています:

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」への名前変更エラー (errno: 150)

一部のグーグルは、これが からの既存の外部キー参照によるものであることを示唆していますchild。本質的に、MySQL に「この他の列を主キーとして使用しますが、元の列の一意のキーであることを忘れないでください」と伝える方法が必要です。childキー制約を削除して後で元に戻す 以外に、これを達成する方法はありますか?

同じデータでコピーを作成して後で交換するのではなく、その場でテーブルを変更する必要があるとします。テーブルを変更する前に使用してみましSET FOREIGN_KEY_CHECKS = 0たが、役に立たないようです。

4

2 に答える 2

8

主キーを削除する前に、old_pk にインデックス (UNIQUE の場合もあります) を追加します。

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)
于 2009-08-05T06:16:44.040 に答える
-4

不人気な提案かもしれないもので、これについて検討します。データベースで外部キー制約を使用しないでください。必要に応じて、ストアド プロシージャで TSQL を介して一意のキーおよびその他の制約を適用してください。私の経験では、スケーリングされた環境ではチェック制約がほとんど使用されません。

私はこれを、反対のコメント/議論に心を開いて言います。この提案が正しいと言っているわけではありません。ただ、私が働いていたショップで一般的な意見でした.

リクエスト:私に反対票を投じる場合は、短いコメントも残してください。私がリレーショナル データベースを扱ってきた 10 年ほどの間に、チェック制約を使用している人は、大規模ではないシステムで作業している人しか知りません。それらが私に反対票を投じる人々である場合、私はそれを受け入れることができます。しかし、スケーリングされたシステムに取り組んでおり、チェック制約が標準である場合、私はあなたが誰であるかを知りたいので、私が見逃しているものを確認するためにいくつかの読書をすることができます.

于 2009-07-28T18:15:59.263 に答える