Query Go
行を更新する - UPDATE の使い方・オプション・サンプル

行を更新する - UPDATE

既存行の値を書き換える。UPDATE ... FROM / JOIN と、WHERE 忘れによる全件更新事故

概念図

UPDATE diagram

構文

sql
UPDATE table SET col = value WHERE 条件;

サンプル

特定ユーザーのステータスを更新する基本形

sql
UPDATE users
SET status = 'active', updated_at = CURRENT_TIMESTAMP
WHERE id = 42;

UPDATE の基本

UPDATE は既存行の値を書き換える DML です。SET 列 = 値 をカンマ区切りで複数指定でき、WHERE で対象行を絞り込みます。

WHERE を書かないと全行が更新されます。後述の事故セクションで扱いますが、まずこの原則を覚えてください。

sql
UPDATE products
SET price = price * 1.1,
    updated_at = CURRENT_TIMESTAMP
WHERE category = 'book';

PostgreSQL の UPDATE ... FROM

PostgreSQL では UPDATE ... FROM で他テーブルを参照しながら更新できます。JOIN 相当の処理を UPDATE で実行する標準的な書き方です。

SQL Server も似た構文(UPDATE ... FROM ... INNER JOIN)をサポートします。

sql
-- PostgreSQL: 注文テーブルから最新金額を反映
UPDATE users u
SET last_order_amount = o.amount
FROM orders o
WHERE o.user_id = u.id
  AND o.ordered_at = (
    SELECT MAX(ordered_at) FROM orders WHERE user_id = u.id
  );

MySQL の UPDATE JOIN

MySQL では UPDATE t1 JOIN t2 ON ... SET ... の構文で JOIN を使った更新を書きます。FROM 句は使えないので PostgreSQL とは方言が異なります。

MariaDB も同様の MySQL 構文に従います。SQLite は UPDATE ... FROM を 3.33 以降でサポート。RDBMS 間の差分は RDBMS 方言早見表 にまとめています。

sql
-- MySQL
UPDATE users u
JOIN orders o ON o.user_id = u.id
SET u.last_order_amount = o.amount
WHERE o.status = 'paid';

大事故: WHERE 忘れによる全件更新

最も有名な事故UPDATE users SET status = 'deleted'; のような WHERE 忘れです。全行が一撃で書き換わり、バックアップ以外で復旧する手段はほぼありません。

  • 対策 1: 本番作業時は必ず BEGIN; で明示トランザクションを開始、件数確認してから COMMIT
  • 対策 2: MySQL なら --safe-updates モードで WHERE なし UPDATE/DELETE を拒否
  • 対策 3: 先に SELECT COUNT(*) FROM ... WHERE ... で件数確認 → 同じ WHERE で UPDATE
  • 対策 4: RETURNING / OUTPUT で影響行を確認してからコミット
sql
-- 事故防止の型
BEGIN;
  SELECT COUNT(*) FROM users WHERE status = 'pending';  -- 件数確認
  UPDATE users SET status = 'active' WHERE status = 'pending';
  -- 想定件数と合えば COMMIT、違えば ROLLBACK
COMMIT;

自己参照 UPDATE と式の評価順

SET a = b, b = a のような自己参照更新を書いたときの評価順は SQL 標準では 更新前の値が使われますが、実装差があります。混乱を避けるため、一時列や CASE 式で明示するのが安全です。

関連トピック