MySQLのエラー『エラー121: Duplicate Key』の解決方法

MySQLのエラー『エラー121: Duplicate Key』の解決方法

MySQLでINSERTやALTER TABLE、CREATE TABLEなどを行った際に「ERROR 121 (HY000): Duplicate key on write or update」が表示される場合がある。このエラーは、主にインデックスや外部キーの重複によって引き起こされる。

1. エラーの発生条件

次のような操作でエラー121が発生する。

  • INSERTで一意キーに既存値を挿入しようとした場合
  • ALTER TABLEで同じ名前のインデックスを作成しようとした場合
  • CREATE TABLEで外部キー名が既に使われている場合
ALTER TABLE orders ADD CONSTRAINT fk_user_id FOREIGN KEY (user_id) REFERENCES users(id);

ERROR 121 (HY000): Duplicate key on write or update

2. INSERT時の一意キー重複による発生

UNIQUEまたはPRIMARY KEYが設定されているカラムに対して、既に存在する値を挿入しようとした場合に発生する。

INSERT INTO users (id, email) VALUES (1, 'test@example.com');

ERROR 1062 (23000): Duplicate entry '1' for key 'PRIMARY'

※この場合、実際のエラーコードは1062だが、複合操作の中で121に変換されるケースがある。

3. CREATE TABLEで外部キー名が重複しているケース

InnoDBで外部キーを設定する際、同一の外部キー名(CONSTRAINT名)を再利用しようとするとエラー121が発生する。

CREATE TABLE orders (
  id INT PRIMARY KEY,
  user_id INT,
  CONSTRAINT fk_user_id FOREIGN KEY (user_id) REFERENCES users(id)
);

すでに別のテーブルで「fk_user_id」という名前の外部キーが使われているとエラーになる。

4. ALTER TABLEでのインデックス名の重複

ALTER TABLEで新しいインデックスや外部キーを追加する際に、すでに同名のインデックスが存在する場合にもこのエラーが発生する。

ALTER TABLE orders ADD CONSTRAINT fk_user_id_orders FOREIGN KEY (user_id) REFERENCES users(id);

自動生成名が被らないようにするためにも、明示的な命名が推奨される。

6. 既存のインデックス・外部キーを確認する

既に定義されているキーや制約名を確認するには、INFORMATION_SCHEMAを使用する。

SELECT CONSTRAINT_NAME
FROM information_schema.TABLE_CONSTRAINTS
WHERE TABLE_NAME = 'orders' AND CONSTRAINT_TYPE = 'FOREIGN KEY';

7. SHOW CREATE TABLEで現在の定義を確認

外部キーやインデックスの状況を視覚的に確認するには、SHOW CREATE TABLEが便利。

SHOW CREATE TABLE orders\G

8. 外部キーを一度削除してから再定義

重複している可能性のあるキーを削除してから、新たに正しく定義し直す。

ALTER TABLE orders DROP FOREIGN KEY fk_user_id;
ALTER TABLE orders ADD CONSTRAINT fk_user_id_orders FOREIGN KEY (user_id) REFERENCES users(id);

9. テーブル削除時にも注意が必要

外部キーが設定されたままのテーブルを再作成しようとすると、エラー121になることがある。その場合、先に外部キーを解除してからDROP TABLEを実行する。

10. mysqldump後のリストアで発生するケース

mysqldumpで複数テーブルをダンプし、順番を入れ替えてインポートすると外部キー重複で121エラーになることがある。–skip-add-drop-tableや–no-create-infoオプションを適宜使用する。

11. 一意キーでのサンプルテーブルとINSERT

CREATE TABLE products (
  id INT PRIMARY KEY,
  code VARCHAR(20) UNIQUE
);

INSERT INTO products (id, code) VALUES (1, 'A001');
-- 以下はエラーになる
INSERT INTO products (id, code) VALUES (2, 'A001');

12. 外部キー名が重複しないようにする命名規則

テーブル名+カラム名をベースに、プロジェクトごとに一貫性のある命名ルールを決めておくと、エラー121の予防になる。

-- Good
CONSTRAINT fk_orders_user_id
-- Bad(他テーブルと被りやすい)
CONSTRAINT fk_user_id