「IDごとに別々の値を一気に更新したい」
「大量データをループせずに高速で処理したい」
「1件ずつ更新するのは時間がかかりすぎる」
そんなときに便利なのが、MySQLのUPDATE複数行一括更新です。
「複数行の更新って難しそう…」
「どんな書き方をすればいいの?」
そんな疑問をお持ちの方も多いでしょう。
実は、いくつかのパターンを覚えれば、効率的にデータを更新できるようになります。
この記事では、MySQLで複数行の異なる値を一度に更新する方法と、効率的な実行パターン、注意点を初心者向けにわかりやすく解説します。
通常のUPDATE文の限界と問題点

一般的なUPDATE文の書き方
基本的な構文
UPDATE users
SET age = 30
WHERE id = 1;
この方法の問題点
通常のUPDATE文は、一つの条件に対して一つの値しか設定できません。
つまり、複数の行に異なる値を設定したい場合は、何回もSQLを実行する必要があります。
非効率なパターンの例
悪い例:繰り返し実行
UPDATE users SET age = 25 WHERE id = 1;
UPDATE users SET age = 30 WHERE id = 2;
UPDATE users SET age = 28 WHERE id = 3;
UPDATE users SET age = 35 WHERE id = 4;
-- ...さらに続く
この方法の問題
- パフォーマンスが悪い:データベースへの接続回数が多い
- 時間がかかる:数百件を更新する場合、非現実的
- トランザクション管理が複雑:途中でエラーが起きた時の処理が大変
- ネットワーク負荷:何度もクエリを送信するため負荷が高い
これらの問題を解決するのが、一括更新のテクニックです。
CASE文+IN句で一括更新する方法【推奨】

基本構文の説明
構文パターン
UPDATE テーブル名
SET カラム名 = CASE 主キー
WHEN 値1 THEN 更新値1
WHEN 値2 THEN 更新値2
WHEN 値3 THEN 更新値3
...
END
WHERE 主キー IN (値1, 値2, 値3, ...);
構文の各部分説明
CASE 主キー
:条件分岐の基準となる列を指定WHEN 値 THEN 更新値
:「もし主キーが○○なら××に更新」という条件WHERE 主キー IN (...)
:更新対象の行を限定(安全性のため重要)
実用的な例:ユーザー年齢の一括更新
実例
UPDATE users
SET age = CASE id
WHEN 1 THEN 25
WHEN 2 THEN 30
WHEN 3 THEN 28
WHEN 4 THEN 35
WHEN 5 THEN 22
END
WHERE id IN (1, 2, 3, 4, 5);
実行結果
id=1
のユーザーは25歳に更新id=2
のユーザーは30歳に更新id=3
のユーザーは28歳に更新id=4
のユーザーは35歳に更新id=5
のユーザーは22歳に更新
なぜこの方法が効率的なのか?
- 1回のSQL実行で複数行を更新
- データベースへの接続は1回だけ
- トランザクション管理が簡単
- 処理速度が大幅に向上
複数カラムを同時に更新する方法

複数カラム更新の基本構文
構文パターン
UPDATE テーブル名
SET
カラム1 = CASE 主キー
WHEN 値1 THEN 更新値1
WHEN 値2 THEN 更新値2
...
END,
カラム2 = CASE 主キー
WHEN 値1 THEN 更新値1
WHEN 値2 THEN 更新値2
...
END
WHERE 主キー IN (値1, 値2, ...);
実用例:商品情報の一括更新
商品価格と在庫を同時更新
UPDATE products
SET
price = CASE id
WHEN 101 THEN 1000
WHEN 102 THEN 1200
WHEN 103 THEN 800
END,
stock = CASE id
WHEN 101 THEN 50
WHEN 102 THEN 30
WHEN 103 THEN 75
END,
last_updated = CASE id
WHEN 101 THEN '2024-01-15'
WHEN 102 THEN '2024-01-15'
WHEN 103 THEN '2024-01-15'
END
WHERE id IN (101, 102, 103);
実行結果
id | price | stock | last_updated |
---|---|---|---|
101 | 1000 | 50 | 2024-01-15 |
102 | 1200 | 30 | 2024-01-15 |
103 | 800 | 75 | 2024-01-15 |
より実践的な例:社員情報の更新
部署異動と昇給を同時処理
UPDATE employees
SET
department = CASE employee_id
WHEN 'E001' THEN '営業部'
WHEN 'E002' THEN '開発部'
WHEN 'E003' THEN '人事部'
END,
salary = CASE employee_id
WHEN 'E001' THEN 350000
WHEN 'E002' THEN 420000
WHEN 'E003' THEN 380000
END,
updated_at = NOW()
WHERE employee_id IN ('E001', 'E002', 'E003');
JOINを使って他テーブルから更新【応用】

JOINによる更新の基本構文
基本パターン
UPDATE 更新対象テーブル t
JOIN 参照テーブル s ON t.結合キー = s.結合キー
SET t.更新カラム1 = s.参照カラム1,
t.更新カラム2 = s.参照カラム2;
実用例:一時テーブルからの一括更新
ケース:CSVインポート後の一括更新
-- 一時テーブルの作成(CSVデータをインポート)
CREATE TEMPORARY TABLE temp_updates (
user_id INT,
new_email VARCHAR(255),
new_phone VARCHAR(20)
);
-- 一時テーブルにデータを挿入
INSERT INTO temp_updates VALUES
(1, 'user1@newdomain.com', '090-1234-5678'),
(2, 'user2@newdomain.com', '090-2345-6789'),
(3, 'user3@newdomain.com', '090-3456-7890');
-- JOINを使った一括更新
UPDATE users u
JOIN temp_updates t ON u.id = t.user_id
SET u.email = t.new_email,
u.phone = t.new_phone,
u.updated_at = NOW();
より高度な例:計算結果による更新
注文合計金額の計算と更新
UPDATE orders o
JOIN (
SELECT
order_id,
SUM(price * quantity) as total_amount
FROM order_items
GROUP BY order_id
) calc ON o.id = calc.order_id
SET o.total_amount = calc.total_amount,
o.updated_at = NOW();
この方法で、注文明細から自動計算した合計金額を注文テーブルに反映できます。
条件付き更新と部分更新

条件に応じた柔軟な更新
特定条件の行のみ更新
UPDATE users
SET status = CASE
WHEN last_login < DATE_SUB(NOW(), INTERVAL 30 DAY) THEN 'inactive'
WHEN last_login < DATE_SUB(NOW(), INTERVAL 7 DAY) THEN 'dormant'
ELSE 'active'
END,
priority = CASE
WHEN subscription_type = 'premium' THEN 1
WHEN subscription_type = 'standard' THEN 2
ELSE 3
END
WHERE id IN (1, 2, 3, 4, 5);
NULL値の条件付き更新
既存値がNULLの場合のみ更新
UPDATE products
SET description = CASE id
WHEN 101 THEN COALESCE(description, '新商品の説明')
WHEN 102 THEN COALESCE(description, '人気商品の説明')
WHEN 103 THEN COALESCE(description, '限定商品の説明')
ELSE description
END
WHERE id IN (101, 102, 103);
パフォーマンス最適化のコツ

インデックスの活用
WHERE句で使用する列にインデックスを設定
-- 主キーは通常自動でインデックスが設定されているが、
-- 他の列を使う場合は明示的に設定
CREATE INDEX idx_users_email ON users(email);
バッチサイズの調整
大量データを分割して処理
-- 悪い例:一度に数万件を更新
UPDATE users SET ... WHERE id IN (1,2,3,...,50000);
-- 良い例:1000件ずつに分割
UPDATE users SET ... WHERE id IN (1,2,3,...,1000);
-- 少し待ってから次のバッチ
UPDATE users SET ... WHERE id IN (1001,1002,...,2000);
更新前後の確認
安全な更新手順
-- 1. 更新対象を事前確認
SELECT id, age FROM users WHERE id IN (1, 2, 3);
-- 2. トランザクション開始
START TRANSACTION;
-- 3. 更新実行
UPDATE users
SET age = CASE id
WHEN 1 THEN 25
WHEN 2 THEN 30
WHEN 3 THEN 28
END
WHERE id IN (1, 2, 3);
-- 4. 結果確認
SELECT id, age FROM users WHERE id IN (1, 2, 3);
-- 5. 問題なければコミット、問題があればロールバック
COMMIT; -- または ROLLBACK;
注意点とベストプラクティス

重要な注意点
注意点 | 内容 | 対策 |
---|---|---|
WHERE句の省略 | 条件なしで実行すると全レコードが更新される | 必ずWHERE句を記述する |
CASEのWHEN重複 | 主キーが重複すると予期しない結果になる | 重複チェックを事前に実行 |
大量データ処理 | 一度に処理すると時間がかかりすぎる | バッチサイズを適切に設定 |
トランザクション | 途中でエラーが起きた時の対応 | トランザクションを使用 |
安全な実行のためのチェックリスト
実行前の確認事項
- バックアップの取得:重要なデータは事前にバックアップ
- テスト環境での検証:本番環境での実行前に必ずテスト
- 影響範囲の確認:どの行が更新されるかを事前に確認
- 処理時間の見積もり:大量データの場合は処理時間を計算
トランザクション管理の例
安全な実行パターン
-- トランザクション開始
START TRANSACTION;
-- 更新実行
UPDATE users
SET age = CASE id
WHEN 1 THEN 25
WHEN 2 THEN 30
WHEN 3 THEN 28
END
WHERE id IN (1, 2, 3);
-- 影響を受けた行数を確認
SELECT ROW_COUNT() as affected_rows;
-- 結果が期待通りなら確定、そうでなければ取り消し
-- COMMIT; または ROLLBACK;
実践的な活用例

ECサイトでの在庫管理
複数商品の在庫を注文に応じて減算
UPDATE products
SET stock = CASE id
WHEN 101 THEN stock - 2 -- 商品101を2個減算
WHEN 102 THEN stock - 1 -- 商品102を1個減算
WHEN 103 THEN stock - 3 -- 商品103を3個減算
END,
last_updated = NOW()
WHERE id IN (101, 102, 103)
AND stock >= CASE id -- 在庫不足チェック
WHEN 101 THEN 2
WHEN 102 THEN 1
WHEN 103 THEN 3
END;
ユーザーのランク更新
購入金額に応じたランク自動更新
UPDATE users u
JOIN (
SELECT
user_id,
SUM(total_amount) as total_purchased
FROM orders
WHERE created_at >= DATE_SUB(NOW(), INTERVAL 1 YEAR)
GROUP BY user_id
) stats ON u.id = stats.user_id
SET u.rank = CASE
WHEN stats.total_purchased >= 100000 THEN 'GOLD'
WHEN stats.total_purchased >= 50000 THEN 'SILVER'
WHEN stats.total_purchased >= 10000 THEN 'BRONZE'
ELSE 'REGULAR'
END,
u.rank_updated_at = NOW();
まとめ
MySQLでの複数行一括UPDATEは、CASE文を使った条件指定が基本であり、大幅なパフォーマンス向上を実現できます。
今回のポイントをおさらい
パターン | 使用場面 | メリット |
---|---|---|
CASE文による更新 | 異なる値に個別更新 | シンプルで理解しやすい |
複数カラム同時更新 | 関連する複数項目を一括変更 | 整合性を保ちながら効率的 |
JOINによる更新 | 他テーブルの値を参照 | 柔軟で高度な更新が可能 |
今日からできること
- 現在の更新処理をCASE文に置き換えてみる
- 複数回実行していたUPDATEを一括化する
- トランザクションを使った安全な更新を実践
- 処理時間を測定してパフォーマンス向上を確認
コメント