MySQLの「ON DUPLICATE KEY UPDATE」とUPSERTを徹底解説!重複データへのスマートな対応術

こんにちは。ゆうせいです。

今回は、MySQLで非常によく使われる便利な構文、「ON DUPLICATE KEY UPDATE」と、いわゆるUPSERT(アップサート)について解説します。

「INSERTしようとしたら、すでに同じデータがあった!」
そんなとき、あなたならどうしますか?

手動で確認してからUPDATEしますか?それともエラーで止めますか?

実は、自動的に「追加 or 更新」をしてくれる構文があるんです。
これを理解すれば、データ処理の幅がぐっと広がりますよ!


そもそもUPSERT(アップサート)とは?

INSERT(追加)+ UPDATE(更新)=UPSERT

UPSERTとは、「Update if exists, Insert if not(存在すれば更新、なければ追加)」の略語です。

まるで、家に誰かがいれば荷物を渡し、いなければポストに入れていく宅配のような動きですね。

MySQLでは、このUPSERTをON DUPLICATE KEY UPDATE構文を使って実現できます。


基本構文:ON DUPLICATE KEY UPDATE

INSERT INTO テーブル名 (カラム1, カラム2, ...)
VALUES (値1, 値2, ...)
ON DUPLICATE KEY UPDATE カラムX = 値X, カラムY = 値Y;

例1:IDが重複していたら更新

INSERT INTO employees (id, name, department)
VALUES (5, '佐藤 太郎', '営業')
ON DUPLICATE KEY UPDATE 
  name = '佐藤 太郎',
  department = '営業';

この構文はこう読みます:

「ID=5がなければ新規追加、あればnamedepartmentを上書きせよ!」


どのキーが重複を引き起こすのか?

対象は「PRIMARY KEY」または「UNIQUEキー」

たとえば、idカラムが主キー(PRIMARY KEY)になっていれば、それが重複の判定基準になります。
また、emailなどにUNIQUE制約を付けていれば、そちらでも発動します。

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

このようなテーブルでは、idまたはemailが重複すればUPSERTが発動します。


特殊な値:VALUES()関数の活用(MySQL 5系まで)

MySQL 5系では、VALUES(カラム名)を使って、INSERTした値を再利用できます。

INSERT INTO products (id, name, price)
VALUES (1, 'みかん', 120)
ON DUPLICATE KEY UPDATE
  price = VALUES(price);

このように書くと、「同じIDの商品があったら、価格だけを上書きする」ことができます。

ただし!MySQL 8.0以降ではこのVALUES()非推奨になりました。
代わりにAS newでエイリアスを使う方法が主流です。


MySQL 8.0以降の書き方(エイリアス使用)

INSERT INTO products (id, name, price)
VALUES (1, 'りんご', 150) AS new
ON DUPLICATE KEY UPDATE
  price = new.price;

この方法なら、将来的にも安心して使えますね!


UPSERTを使うときの注意点

UPDATEされるのは明示したカラムだけ

たとえば、以下のように書いたとしましょう:

ON DUPLICATE KEY UPDATE updated_at = NOW();

この場合、重複が起きてもupdated_atしか更新されません。
ほかのカラムはそのままです。


副作用に注意

UPSERTは便利な反面、以下のような注意点があります:

注意点内容
トリガーが2回動く可能性ありINSERT → UPDATEの順に発火
ログが煩雑になるデータベースログの可読性に影響
複雑なUPDATEだと遅くなる条件分岐が多い場合は分けた方が安全

UPSERTが特に便利なシーン

  • ユーザーが初回アクセス時はINSERT、再ログイン時はUPDATE
  • 外部システムから定期的に情報を取り込むとき
  • 「存在チェック → 分岐してINSERTかUPDATE」する処理を1文で済ませたいとき

これらの処理がたった1行でスマートに書けるのは、本当に助かります!


DELETEとの組み合わせには注意!

UPSERTの真逆がDELETEです。
「なければINSERT」ではなく「あるなら削除」するような処理は、UPSERTではなく別途制御ロジックを使いましょう。


今後の学習ステップ

UPSERTをマスターしたら、次に学ぶべき内容は次のとおりです:

  • MERGE文(標準SQLに近い):MySQLにはまだ実装されていませんが、他のDBではよく使われます
  • REPLACE INTO構文:既存レコードを削除→新規INSERT(ただし副作用が強い)
  • トランザクションとロックの理解:複数のUPSERTが同時に走ったときの挙動を制御

また、「条件付きで一部だけ更新したい」といったニーズには、CASE文との組み合わせもおすすめです。

セイ・コンサルティング・グループの新人エンジニア研修のメニューへのリンク

投稿者プロフィール

山崎講師
山崎講師代表取締役
セイ・コンサルティング・グループ株式会社代表取締役。
岐阜県出身。
2000年創業、2004年会社設立。
IT企業向け人材育成研修歴業界歴20年以上。
すべての無駄を省いた費用対効果の高い「筋肉質」な研修を提供します!
この記事に間違い等ありましたらぜひお知らせください。