UPDATE 文でデータを更新する
1 人だけ直すつもりが、全員書き換わる
会員 1 人を無料プランに戻したくて、こう打ったとします。
SQL クエリ
UPDATE members SET plan = 'free';WHERE がありません。これで全会員が無料プランになります。データベースはこれを事故と見なさず、正常終了として「更新した件数」を返すだけです。しかも UPDATE は元の値を上書きする命令なので、誰がどのプランだったかは、どこにも残りません。
正しくは、WHERE で対象を絞ります。
SQL クエリ
UPDATE members
SET plan = 'free',
updated_at = NOW()
WHERE id = 47;SET に「何を入れるか」、WHERE に「どの行か」を書きます。変えたい列が複数あるときは、SET の中をカンマで並べます。構文としてはこれだけで、難しいのは 2 行目ではなく 4 行目のほうです。
流す前に、同じ WHERE のまま SELECT する
UPDATE を書いたら、実行する前に必ず先頭を SELECT に置き換えて、WHERE はそのままで一度流します。
SQL クエリ
-- 1. まず対象を見る ここで件数と中身を確認する
SELECT id, name, plan
FROM members
WHERE plan = 'trial' AND created_at < '2026-01-01';
-- 2. 想定どおりなら、WHERE をそのままにして UPDATE を流す
UPDATE members
SET plan = 'free'
WHERE plan = 'trial' AND created_at < '2026-01-01';5 件のつもりが 3,000 件返ってきた、という食い違いは、この一手間があるときにだけ見つかります。条件を AND で 2 つ以上つないだときほど効きます。片方を書き落としていても SQL 自体は正しく動いてしまうので、動いたかどうかでは気付けないからです。
WHERE は書き直さず、コピーして貼ってください。手で打ち直すと、確認したものと流すものが別物になります。
今入っている値を使って、足し引きする
SET の右辺には、その行に今入っている値も書けます。
SQL クエリ
UPDATE members
SET point = point - 500
WHERE id = 47;point = point - 500 は「今の point から 500 を引いた値を入れる」という意味です。掛け算も同じように書けます。
この書き方には、読んでから書き戻すまでの往復が要らないという利点があります。アプリ側で今の値を取得し、計算して、書き戻す、という手順を踏むと、その間に別の処理が同じ行を更新したときに、片方の変更が消えます。データベースの中で計算させれば、その隙間がなくなります。
テーブル構造
CREATE TABLE products (
id INT PRIMARY KEY,
name VARCHAR(100) NOT NULL,
price INT NOT NULL,
stock INT NOT NULL,
category_id INT NOT NULL
);
INSERT INTO products (id, name, price, stock, category_id) VALUES
(1, 'ノートPC', 100000, 10, 1),
(2, 'ワイヤレスマウス', 3000, 50, 1),
(3, '外付けSSD 1TB', 14000, 20, 1),
(4, 'ボールペン', 150, 200, 2),
(5, 'ノートB5', 200, 300, 2);期待される出力
| id | name | price | stock |
|---|---|---|---|
| 1 | ノートPC | 100000 | 7 |
| 2 | ワイヤレスマウス | 3000 | 50 |
| 3 | 外付けSSD 1TB | 14000 | 20 |
| 4 | ボールペン | 165 | 200 |
| 5 | ノートB5 | 220 | 300 |