UPDATE の使い方
shain社員
| name | busho_id | salary |
|---|---|---|
| 中村 | 2 | 530000 |
| 佐藤 | 2 | 720000 |
| 井上 | 7 | 505000✕ |
| 伊藤 | 3 | 530000✕ |
| … | ||
WHERE で対象を選ぶ書き換わる行
| name | busho_id | salary |
|---|---|---|
| 中村 | 2 | 530000 |
| 佐藤 | 2 | 720000 |
| … | ||
WHERE busho_id = 2
- 取り消し線= 条件に合わないので結果に出てこない行
- 社員 18 行 → 書き換わる行 4 行(14 行が消えます)
取り消し線の行は対象外です。WHERE を書かないと、この線がすべて消えて全行が対象になります。
UPDATE はすでにある行の値を書き換える文です。危険なのは WHERE の書き忘れで、1 行のつもりが全行変わります。しかも元に戻せません。実行する前に、同じ条件で SELECT して対象を確かめる癖をつけてください。
主要 7 製品で通用 そのまま使える: PostgreSQL / MySQL / MariaDB / SQLite / SQL Server / Oracle Database / IBM Db2
このページの実行結果と図は、すべて本物のデータベースに同じ SQL を流して得たものです。手で書いた「たぶんこうなる」ではありません。
01基本形は UPDATE … SET … WHERE
結論: `UPDATE 表 SET 列 = 値 WHERE 条件` の 3 つで書きます。
SET に書くのは「新しい値」、WHERE に書くのは「どの行を変えるか」です。WHERE を省略すると表の全行が対象になります。
このページの例では RETURNING を付けています。更新した行をその場で返す書き方で、何がどう変わったかを 1 文で確かめられます。
⚠️ RETURNING は PostgreSQL・SQLite・MariaDB で使えます。SQL Server は OUTPUT、MySQL には相当するものがありません。確認のために `SELECT` を別に流すのが、どの製品でも通るやり方です。
UPDATE shainどの表を変えるかSET salary = salary + 10000新しい値(式も書ける)WHERE busho_id = 2どの行を変えるかRETURNING name, salary変えた行を返す(確認用)
WHERE を消すと全行が対象になります。書き忘れがいちばん多い事故です。
SELECT shain_id, name, salary FROM shain WHERE busho_id = 2 ORDER BY shain_id;| shain_id | name | salary |
|---|---|---|
| 2 | 佐藤 | 720000 |
| 3 | 田中 | 520000 |
| 4 | 中村 | 530000 |
| 5 | 小林 | 445050 |
(4 行)
UPDATE を書く前に、同じ WHERE で SELECT します。件数と中身がここで分かります。
UPDATE shain SET salary = salary + 10000 WHERE busho_id = 2 RETURNING shain_id, name, salary - 10000 AS mae, salary AS ato;| shain_id | name | mae | ato |
|---|---|---|---|
| 2 | 佐藤 | 720000 | 730000 |
| 3 | 田中 | 520000 | 530000 |
| 4 | 中村 | 530000 | 540000 |
| 5 | 小林 | 445050 | 455050 |
(4 行)
4 行だけが返っています。RETURNING には式も書けるので、変更前の値を計算して並べられます。
02⚠️ WHERE を書き忘れると全行が変わる
結論: `WHERE` の無い `UPDATE` は表の全行を書き換えます。
エラーにも警告にもなりません。実行した瞬間に、関係のない行まで値が変わります。
この演習環境は「初期状態に戻す」で元に戻せますが、本番のデータベースでは戻せません。UPDATE を書くときは、先に WHERE を書いてから SET を書く、という順番にすると忘れにくくなります。
実務では次の 2 つが効きます。
- トランザクションの中で試す。
BEGIN;で始めてUPDATEを流し、件数を確かめてからCOMMIT;(違えばROLLBACK;) - 更新された行数を見る。想定と違う件数が返ったら、そこで止まって条件を見直す
UPDATE shain SET salary = 999999 RETURNING shain_id, name, salary;| shain_id | name | salary |
|---|---|---|
| 1 | 鈴木 | 999999 |
| 2 | 佐藤 | 999999 |
| 3 | 田中 | 999999 |
| 4 | 中村 | 999999 |
| 5 | 小林 | 999999 |
| 6 | 加藤 | 999999 |
(18 行 … うち先頭 6 行を表示)
18 行が返りました。返ってきた行数がそのまま「変えてしまった行数」です。4 行のつもりが 18 行なら、そこで気づけます。
03SET に CASE を書いて出し分ける
結論: `SET` の右辺には `CASE` を書けます。行ごとに違う値を入れられます。
⚠️ このとき `ELSE` を書かないと、条件に合わない行が `NULL` になります。「変えない」は ELSE 列名 と明示してください。
この表の salary には NOT NULL が付いているので、ELSE を省くとエラーで止まります。制約が事故を防いでくれた形です。制約が無い列なら、そのまま値が消えていました。
UPDATE shain SET salary = CASE WHEN busho_id = 3 THEN salary + 20000 ELSE salary END RETURNING shain_id, busho_id, salary;| shain_id | busho_id | salary |
|---|---|---|
| 1 | 1 | 980000 |
| 2 | 2 | 720000 |
| 3 | 2 | 520000 |
| 4 | 2 | 530000 |
| 5 | 2 | 445050 |
| 6 | 5 | 610000 |
| 7 | 5 | 468000 |
| 8 | 3 | 720000 |
(18 行 … うち先頭 8 行を表示)
ELSE salary が「変えない」を表します。全 18 行が返るのは、全行が更新の対象になっているためです(値は変わらなくても対象ではあります)。
UPDATE shain SET salary = CASE WHEN busho_id = 3 THEN salary + 20000 END;営業部以外が NULL になろうとして、NOT NULL 制約に阻まれました。制約が無ければ、静かに値が消えていたところです。
04他の表を見て対象を決める
結論: `WHERE` に副問い合わせを書けば、別の表の条件で対象を選べます。
部署番号を直接書くと、番号が変わったときに黙って別の部署を更新してしまいます。名前から引けば、意図が SQL の中に残ります。
対象が複数になるときは IN を使います。= は 1 つの値としか比べられないので、副問い合わせが 2 行以上返すとエラーになります。
UPDATE shain SET salary = salary + 5000 WHERE busho_id = (SELECT busho_id FROM busho WHERE busho_name = '管理') RETURNING shain_id, name, salary;| shain_id | name | salary |
|---|---|---|
| 14 | 清水 | 655000 |
| 15 | 斎藤 | 460000 |
| 16 | 山本 | 517000 |
(3 行)
番号ではなく名前で指定しています。組織の番号が変わっても意図は壊れません。返ってきた 3 行が管理部の社員です。
UPDATE shain SET salary = salary + 5000 WHERE busho_id = (SELECT busho_id FROM busho WHERE parent_busho_id = 1);最上位部署の直下は複数あるため、= では受け取れません。次の例のように IN を使います。
UPDATE shain SET salary = salary + 5000 WHERE busho_id IN (SELECT busho_id FROM busho WHERE parent_busho_id = 1) RETURNING shain_id, busho_id, salary;| shain_id | busho_id | salary |
|---|---|---|
| 2 | 2 | 725000 |
| 3 | 2 | 525000 |
| 4 | 2 | 535000 |
| 5 | 2 | 450050 |
| 8 | 3 | 705000 |
| 9 | 3 | 485000 |
| 10 | 3 | 535000 |
| 11 | 3 | 426000 |
| 14 | 4 | 655000 |
| 15 | 4 | 460000 |
| 16 | 4 | 517000 |
(11 行)
IN なら複数行を受け取れます。返ってきた行の busho_id を見れば、対象の部署が意図どおりか確かめられます。
05更新できないこともある
結論: 制約に反する値には更新できません。
この表の salary には「0 より大きい」という検査制約が付いています。それに反する値を入れようとすると、更新は行われずにエラーになります。
エラーで止まるのは安全側の動きです。何も起きなかったのではなく、制約が守ってくれたと読んでください。1 行でも制約に反すると、その文全体が取り消されます。一部だけ更新されて中途半端に終わることはありません。
UPDATE shain SET salary = 0 WHERE shain_id = 1;salary > 0 という検査制約があるため拒否されます。表の定義が誤ったデータを防いでいます。
UPDATE shain SET salary = CASE WHEN shain_id = 1 THEN 0 ELSE salary + 1000 END;他の 17 人は正しい値だったのに、1 人が制約に反したため何も更新されていません。文の単位で全部通るか全部やめるかが決まります。
自分で打ってみる
このページの例と同じデータが入った本物のデータベースを、この場(あなたのブラウザの中)で起動できます。打った SQL がサーバーへ送られることはありません。
押すと初回だけ約 9MB を読み込みます(2 回目以降はキャッシュされます)。
解いてみる
読んだだけでは書けるようになりません。実行結果で採点します。
関連するトピック
- DELETE(練習問題)行を消す DELETE も、WHERE の書き忘れが同じ事故になります。
- WHERE 句対象を決めるのは WHERE です。書き方はここで扱っています。
- CASE 式(練習問題)SET の中で値を出し分けるときに使います。ELSE の省略に注意してください。
根拠(一次情報)
- PostgreSQL 18 マニュアル: UPDATE一次情報・確認 2026-08-02
- PostgreSQL 18 マニュアル: データの更新一次情報・確認 2026-08-02