MySQL/MariaDB初心者でも安心!「errno: 121 Duplicate key on write or update」エラーの基礎知識と解決のヒント

2024-05-26

MySQL/MariaDB で errno: 121 "Duplicate key on write or update" エラーが発生する原因と解決策

MySQL/MariaDB でテーブルを作成する際、CONSTRAINT を使用して主キーやユニークキーを定義することがあります。しかし、CONSTRAINT で定義した制約に違反するようなデータ挿入や更新操作を実行しようとすると、errno: 121 "Duplicate key on write or update" エラーが発生します。

エラーの原因

このエラーが発生する主な原因は以下の2つです。

  1. 主キー/ユニークキーに重複する値を挿入/更新しようとしている

解決策

このエラーを解決するには、以下の方法があります。

  1. 重複する値を挿入/更新しない

  2. 主キー/ユニークキーの値を変更する

以下の例は、主キーに重複する値を挿入しようとした場合のエラーと、IGNORE オプションを使用することでエラーを回避する方法を示しています。

-- 主キーに重複する値を挿入しようとするとエラーが発生
INSERT INTO users (id, name) VALUES (1, 'John Doe');

-- エラーメッセージ: Duplicate key on write or update

-- IGNORE オプションを使用することでエラーを回避
INSERT IGNORE INTO users (id, name) VALUES (1, 'Jane Doe');
  • このエラーは、UPDATE 文でも発生します。
  • CONSTRAINT で定義した制約以外にも、NOT NULL 制約や外部キー制約など、様々な制約違反によってこのエラーが発生する可能性があります。
  • エラーメッセージの詳細を確認することで、エラーの原因を特定することができます。

    補足

    この説明は、MySQL/MariaDB の基本的な動作を理解していることを前提としています。もし、MySQL/MariaDB の基本的な知識がない場合は、まずそちらを学習してからこの説明を読むことをお勧めします。




    例1:主キーに重複する値を挿入

    この例では、users テーブルに主キー id を持つレコードを2つ挿入しようとします。2番目のレコードの id は1ですが、これは1番目のレコードと重複するため、エラーが発生します。

    CREATE TABLE users (
      id INT PRIMARY KEY,
      name VARCHAR(255)
    );
    
    INSERT INTO users (id, name) VALUES (1, 'John Doe');
    INSERT INTO users (id, name) VALUES (1, 'Jane Doe');
    

    出力

    ERROR 121 (Duplicate key on write or update): Duplicate entry '1' for key 'PRIMARY'
    

    以下のいずれかの方法で解決できます。

    • 2番目のレコードの id を変更する
    • INSERT 文に IGNORE オプションを使用する
    CREATE TABLE users (
      id INT PRIMARY KEY,
      name VARCHAR(255)
    );
    
    INSERT INTO users (id, name) VALUES (1, 'John Doe');
    INSERT IGNORE INTO users (id, name) VALUES (1, 'Jane Doe');
    
    1 row affected
    

    この例では、users テーブルの email 列がユニークキーであることを想定しています。email 列に同じ値を持つレコードを2つ更新しようとすると、エラーが発生します。

    CREATE TABLE users (
      id INT PRIMARY KEY,
      name VARCHAR(255),
      email VARCHAR(255) UNIQUE
    );
    
    INSERT INTO users (id, name, email) VALUES (1, 'John Doe', '[email protected]');
    INSERT INTO users (id, name, email) VALUES (2, 'Jane Doe', '[email protected]');
    
    UPDATE users SET email = '[email protected]' WHERE id = 1;
    
    ERROR 121 (Duplicate key on write or update): Duplicate entry '[email protected]' for key 'email'
    
    • 更新しようとしているレコードの email を変更する

    この例では、orders テーブルと products テーブルがあり、orders テーブルの product_id 列は products テーブルの id 列を参照する外部キー制約であることを想定しています。orders テーブルに存在しない product_id を持つレコードを挿入しようとすると、エラーが発生します。

    CREATE TABLE products (
      id INT PRIMARY KEY
    );
    
    CREATE TABLE orders (
      id INT PRIMARY KEY,
      product_id INT,
      FOREIGN KEY (product_id) REFERENCES products(id)
    );
    
    INSERT INTO products (id) VALUES (1);
    INSERT INTO orders (id, product_id) VALUES (1, 2);
    
    ERROR 145 (Constraint violation): Cannot insert value '2' into 'product_id'. 'product_id' doesn't exist in table 'products'
    
    • 挿入しようとしているレコードの product_id を、products テーブルに存在する値に変更する
    • 外部キー制約を削除する(非推奨

    これらの例は、errno: 121 "Duplicate key on write or update" エラーの一般的な原因と解決策を示しています。エラーが発生した場合は、エラーメッセージの詳細を確認し、適切な解決策を選択してください。

    • このサンプルコードは、MySQL/MariaDB 8.0.26 で動作確認しています。
    • 実際のデータベーススキーマやデータは、状況によって異なる場合があります。



    MySQL/MariaDB で errno: 121 "Duplicate key on write or update" エラーを解決するその他の方法

    ユニークインデックスを使用する

    主キー以外にも、ユニークインデックスを使用して列の重複を防止することができます。ユニークインデックスは、主キーと同様に、列の値が一意であることを保証します。

    以下の例では、users テーブルの email 列にユニークインデックスを作成します。

    CREATE TABLE users (
      id INT PRIMARY KEY,
      name VARCHAR(255),
      email VARCHAR(255),
      UNIQUE KEY email_idx (email)
    );
    

    INSERT 文や UPDATE 文を排他ロックで実行することで、他のトランザクションが同じ行を更新/挿入するのをブロックすることができます。

    以下の例では、users テーブルの id = 1 のレコードを排他ロックで更新します。

    BEGIN TRANSACTION;
    
    UPDATE users SET name = 'Jane Doe' WHERE id = 1 FOR UPDATE;
    
    COMMIT;
    

    アプリケーションロジックを変更して、重複するデータを挿入/更新しないようにすることができます。

    以下の例は、レコードを挿入する前に、同じレコードが存在しないかどうかをチェックする擬似コードです。

    function insertUser(name, email):
      if existsUser(email):
        error("Email already exists")
        return
    
      INSERT INTO users (name, email) VALUES (name, email);
    

    競合解決メカニズムを使用する

    データベースによっては、ロックや分散トランザクションなどの競合解決メカニズムを提供している場合があります。これらのメカニズムを使用して、並行実行されるトランザクション間の競合を解決することができます。

    注意事項

    上記で紹介した方法は、いずれも状況によって適切かどうかを判断する必要があります。例えば、排他ロックを使用すると、データベースのパフォーマンスが低下する可能性があります。また、アプリケーションロジックを変更する場合は、コードが複雑になる可能性があります。

    最適な解決策を選択するには

    • エラーが発生する頻度と影響範囲
    • データベースのパフォーマンス要件
    • アプリケーションのアーキテクチャ

    などを考慮する必要があります。

      errno: 121 "Duplicate key on write or update" エラーは、様々な原因で発生します。適切な解決策を選択するには、エラーの原因を特定し、状況を考慮する必要があります。


      mysql mariadb


      MySQLで最初のN件の結果をスキップする:初心者から上級者まで使えるテクニック集

      LIMIT句は、結果として返される行数を指定するために使用されます。例えば、以下のクエリは、usersテーブルから最初の10件のレコードのみを返します。OFFSET句は、LIMIT句と組み合わせて使用し、最初のN件の行をスキップして、そのN番目以降の行を返すために使用されます。例えば、以下のクエリは、usersテーブルから11番目以降のレコードのみを返します。...


      【保存版】MySQLの接続情報を徹底解説! コマンドからツールまで

      SHOW GLOBAL STATUS コマンドは、MySQL サーバ全体のグローバルなステータス情報を表示します。このコマンドに LIKE '%connect%' オプションを指定することで、接続情報に関連するステータス変数を絞り込むことができます。...


      【初心者向け】PHPでデータベース接続エラー「mysql_connect(): [2002] No such file or directory (trying to connect via unix:///tmp/mysql.sock) in」を解決する3つのステップ

      このエラーは、PHPスクリプトがMySQLデータベースに接続しようとした際に、ソケットファイル /tmp/mysql. sock が存在しない、またはアクセス権限がないために発生します。原因以下の原因が考えられます。MySQLサーバーが起動していない...


      MySQLでカラムのデフォルト値を変更する方法:ALTER TABLEステートメント、その他の方法、サンプルコード

      方法1:DEFAULTキーワードを使用するこの方法は、デフォルト値を単純な値に変更する場合に便利です。例:この例では、usersテーブルのageカラムのデフォルト値を20に変更します。この方法は、デフォルト値だけでなく、データ型やその他の属性も変更する場合に便利です。...


      HAproxyステータスがDOWNの原因と解決策:ロードバランシングとMariaDBにおける詳細解説

      HAproxyステータスがDOWNになる問題は、ロードバランシングとMariaDB環境において深刻な問題です。この状態では、MariaDBデータベースへのアクセスが途絶え、アプリケーションやサービスが正常に動作しなくなります。本記事では、HAproxyステータスがDOWNになる原因、詳細なトラブルシューティング手順、予防策について、分かりやすく日本語で解説します。...


      SQL SQL SQL SQL Amazon で見る



      MySQLエラー1005「テーブル作成失敗(errno: 121)」の原因と解決策を徹底解説!

      原因このエラーにはいくつかの考えられる原因があります。最も一般的なものは次のとおりです。重複するテーブル名: すでに同じ名前のテーブルが存在する可能性があります。テーブル名は大文字小文字を区別するため、大小文字の違いであっても問題が発生する可能性があります。