SQLでテーブルの全レコードを一括で更新するには、UPDATE文を使います。WHERE句を省略すれば全行が対象になり、WHERE句を付ければ条件に合う行だけを更新できます。
この記事では、UPDATE文の基本構文から、WHERE条件付き更新、複数カラムの同時更新、CASE WHENでの行ごとの振り分け、サブクエリ・JOINを使った高度な更新、NULLの取り扱い、安全に実行するためのテクニックまで、実務で必要な知識を網羅的に解説します。
この記事で学べること
- UPDATE文の基本構文と全レコード一括更新の方法
- WHERE句で条件を指定した部分更新
- 複数カラムを同時に更新する書き方
- CASE WHENで行ごとに異なる値を設定する方法
- サブクエリを使った別テーブル参照の更新
- UPDATE … JOIN(MySQL / 標準SQL)の使い分け
- NULLの取り扱い(SET NULL・COALESCE)
- 安全に実行するコツ(BEGIN/ROLLBACK・SELECT事前確認・LIMIT)
- よくあるエラーと対処法
- RDBMS別(MySQL / PostgreSQL / SQL Server / Oracle)の違い
サンプルデータ
この記事では以下の employees テーブルを使って解説します。
| id |
name |
department |
salary |
| 1 |
田中太郎 |
営業 |
350000 |
| 2 |
鈴木花子 |
開発 |
420000 |
| 3 |
佐藤一郎 |
営業 |
300000 |
| 4 |
高橋美咲 |
開発 |
380000 |
| 5 |
山田健太 |
人事 |
280000 |
| 6 |
伊藤恵 |
人事 |
320000 |
| 7 |
渡辺大輔 |
開発 |
450000 |
| 8 |
中村由美 |
営業 |
280000 |
テーブル作成・データ挿入SQL(クリックで展開)
CREATE TABLE + INSERT
CREATE TABLE employees (
id INT PRIMARY KEY,
name VARCHAR(50),
department VARCHAR(50),
salary INT
);
INSERT INTO employees (id, name, department, salary) VALUES
(1, '田中太郎', '営業', 350000),
(2, '鈴木花子', '開発', 420000),
(3, '佐藤一郎', '営業', 300000),
(4, '高橋美咲', '開発', 380000),
(5, '山田健太', '人事', 280000),
(6, '伊藤恵', '人事', 320000),
(7, '渡辺大輔', '開発', 450000),
(8, '中村由美', '営業', 280000);
UPDATE文の基本構文(全レコード更新)
UPDATE文は、テーブルのデータを更新するためのSQL文です。WHERE句を省略すると、テーブル内の全レコードが更新対象になります。
基本構文
UPDATE テーブル名
SET カラム名 = 新しい値;
実行例:全社員の部署を一括変更
全レコード一括更新
-- 全社員の部署を「総務」に変更
UPDATE employees
SET department = '総務';
実行結果
Query OK, 8 rows affected (0.01 sec)
Rows matched: 8 Changed: 8 Warnings: 0
WHERE句がないため、8件すべてのレコードの department が「総務」に更新されます。
計算式を使った一括更新
SET句では計算式も使えます。全社員の給与を一律10%アップする例です。
計算式で一括更新
-- 全社員の給与を10%アップ
UPDATE employees
SET salary = salary * 1.1;
実行結果(更新後の確認)
id | name | department | salary
----+----------+------------+--------
1 | 田中太郎 | 営業 | 385000
2 | 鈴木花子 | 開発 | 462000
3 | 佐藤一郎 | 営業 | 330000
4 | 高橋美咲 | 開発 | 418000
5 | 山田健太 | 人事 | 308000
6 | 伊藤恵 | 人事 | 352000
7 | 渡辺大輔 | 開発 | 495000
8 | 中村由美 | 営業 | 308000
注意:WHERE句なしのUPDATEは全行に影響します。本番環境では誤って実行すると取り返しがつかないため、必ず事前にSELECTで確認してください。
WHERE句で条件を指定して更新する
WHERE句を付けると、条件に一致するレコードだけを更新できます。実務ではほとんどのUPDATEにWHERE句を付けるのが基本です。
WHERE句付きの構文
UPDATE テーブル名
SET カラム名 = 新しい値
WHERE 条件;
特定のIDを指定して更新
IDを指定して更新
-- ID=3 の佐藤一郎の給与を350000に変更
UPDATE employees
SET salary = 350000
WHERE id = 3;
複数条件での更新(AND / OR)
複数条件
-- 営業部で給与が300000未満の社員の給与を300000に引き上げ
UPDATE employees
SET salary = 300000
WHERE department = '営業'
AND salary < 300000;
実行結果
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
→ id=8 中村由美の salary が 280000 → 300000 に更新
IN句で複数の値にマッチさせる
IN句で複数指定
-- ID が 1, 3, 8 の社員の部署を「マーケティング」に変更
UPDATE employees
SET department = 'マーケティング'
WHERE id IN (1, 3, 8);
複数カラムを同時に更新する
カンマ区切りで複数のカラムをまとめて更新できます。1回の UPDATE 文で処理するため、複数回に分けるよりも効率的です。
複数カラムを同時更新
-- ID=5 の山田健太:部署と給与を同時に変更
UPDATE employees
SET department = '開発',
salary = 350000
WHERE id = 5;
実行結果(更新後の確認)
id | name | department | salary
----+----------+------------+--------
5 | 山田健太 | 開発 | 350000
全レコードの複数カラムを一括更新
全レコードの複数カラム更新
-- 全社員:部署を「未定」、給与を0にリセット
UPDATE employees
SET department = '未定',
salary = 0;
ポイント:SET句の各カラムはカンマ区切りで並べます。最後のカラムの後にはカンマを付けないでください(構文エラーになります)。
CASE WHENで行ごとに異なる値を設定する
CASE WHENを使うと、条件に応じて行ごとに異なる値を設定できます。1回のUPDATEで複雑な振り分けを実現できるため、非常に便利です。
部署ごとに異なる昇給率を適用する
CASE WHEN で条件分岐
-- 部署ごとに異なる昇給率を適用
UPDATE employees
SET salary = CASE
WHEN department = '開発' THEN salary * 1.15 -- 開発: 15%アップ
WHEN department = '営業' THEN salary * 1.10 -- 営業: 10%アップ
WHEN department = '人事' THEN salary * 1.05 -- 人事: 5%アップ
ELSE salary -- その他: 変更なし
END;
実行結果(更新後の確認)
id | name | department | salary
----+----------+------------+--------
1 | 田中太郎 | 営業 | 385000 (350000 × 1.10)
2 | 鈴木花子 | 開発 | 483000 (420000 × 1.15)
3 | 佐藤一郎 | 営業 | 330000 (300000 × 1.10)
4 | 高橋美咲 | 開発 | 437000 (380000 × 1.15)
5 | 山田健太 | 人事 | 294000 (280000 × 1.05)
6 | 伊藤恵 | 人事 | 336000 (320000 × 1.05)
7 | 渡辺大輔 | 開発 | 517500 (450000 × 1.15)
8 | 中村由美 | 営業 | 308000 (280000 × 1.10)
IDを指定して個別に値を設定する
IDごとに個別の値を設定
-- 特定の社員だけ部署を変更
UPDATE employees
SET department = CASE id
WHEN 1 THEN 'マーケティング'
WHEN 5 THEN '経理'
WHEN 8 THEN '開発'
ELSE department
END
WHERE id IN (1, 5, 8);
ポイント:CASE WHEN で全行を対象にする場合、ELSE句で現在の値を返すことで、条件に当てはまらない行を変更しないようにできます。WHERE句でさらに対象を絞れば無駄な更新を減らせます。
サブクエリを使った更新(UPDATE … SET col = (SELECT …))
サブクエリを使うと、別のテーブルの値を参照して更新できます。集計値やマスタデータを反映する場合に便利です。
部署ごとの平均給与で全社員を更新する
サブクエリで平均給与に更新
-- 各社員の給与を、所属部署の平均給与に更新
UPDATE employees e1
SET salary = (
SELECT AVG(e2.salary)
FROM employees e2
WHERE e2.department = e1.department
);
実行結果(更新後の確認)
id | name | department | salary
----+----------+------------+--------
1 | 田中太郎 | 営業 | 310000 (営業の平均)
2 | 鈴木花子 | 開発 | 416667 (開発の平均)
3 | 佐藤一郎 | 営業 | 310000
4 | 高橋美咲 | 開発 | 416667
5 | 山田健太 | 人事 | 300000 (人事の平均)
6 | 伊藤恵 | 人事 | 300000
7 | 渡辺大輔 | 開発 | 416667
8 | 中村由美 | 営業 | 310000
別テーブルの値を参照して更新する
マスタテーブルの値を元に更新するパターンです。
別テーブル参照の更新
-- departments マスタの基本給を employees に反映
UPDATE employees
SET salary = (
SELECT d.base_salary
FROM departments d
WHERE d.dept_name = employees.department
);
注意:サブクエリが複数行を返すとエラーになります。必ずサブクエリの結果が1行以下になるようにしてください。一致するデータがない場合はNULLが設定されるため、COALESCEでデフォルト値を指定するとより安全です。
UPDATE … JOIN(MySQL vs 標準SQL)
複数テーブルを結合して更新する場合、MySQLと標準SQL(PostgreSQL・SQL Server等)で構文が異なります。
MySQL:UPDATE … JOIN構文
MySQL – UPDATE … JOIN
-- MySQL: departments テーブルの基本給を反映
UPDATE employees e
INNER JOIN departments d
ON e.department = d.dept_name
SET e.salary = d.base_salary;
標準SQL(PostgreSQL):UPDATE … FROM構文
PostgreSQL – UPDATE … FROM
-- PostgreSQL: departments テーブルの基本給を反映
UPDATE employees e
SET salary = d.base_salary
FROM departments d
WHERE e.department = d.dept_name;
SQL Server:UPDATE … FROM構文
SQL Server – UPDATE … FROM … JOIN
-- SQL Server: departments テーブルの基本給を反映
UPDATE e
SET e.salary = d.base_salary
FROM employees e
INNER JOIN departments d
ON e.department = d.dept_name;
Oracle:MERGEを使う方法
Oracle – MERGE
-- Oracle: MERGE で結合更新
MERGE INTO employees e
USING departments d
ON (e.department = d.dept_name)
WHEN MATCHED THEN
UPDATE SET e.salary = d.base_salary;
ポイント:JOIN を使った UPDATE は、サブクエリよりも読みやすく高速な場合が多いです。ただし構文がRDBMSごとに異なるため、使用するDBに合った書き方を選びましょう。
UPDATEでのNULLの取り扱い
UPDATEでカラムを NULL にしたり、NULL値を別の値に置き換えたりする方法を解説します。
カラムをNULLに更新する
NULLに更新
-- ID=3 の部署をNULLに設定
UPDATE employees
SET department = NULL
WHERE id = 3;
NULL はクォーテーションで囲みません。'NULL'(文字列)と NULL(値なし)はまったく別物です。
COALESCEでNULLをデフォルト値に置き換える
COALESCEでNULL回避
-- department が NULL の社員を「未配属」に更新
UPDATE employees
SET department = '未配属'
WHERE department IS NULL;
-- サブクエリの結果がNULLの場合にデフォルト値を使う
UPDATE employees
SET salary = COALESCE(
(SELECT d.base_salary
FROM departments d
WHERE d.dept_name = employees.department),
300000 -- マッチしなければ300000を設定
);
ポイント:COALESCE(値1, 値2)は、値1がNULLなら値2を返す関数です。サブクエリの結果がNULLになりうる場合に安全策として使えます。
UPDATEを安全に実行するためのコツ
UPDATE文は一度実行すると元に戻せません(COMMIT後)。本番環境で事故を防ぐために、以下のテクニックを身につけましょう。
1. トランザクションで囲む(BEGIN / ROLLBACK)
トランザクションで安全に実行
BEGIN; -- トランザクション開始
-- 更新を実行
UPDATE employees
SET salary = salary * 1.1
WHERE department = '開発';
-- 結果を確認
SELECT * FROM employees WHERE department = '開発';
-- 問題なければ確定、問題あれば取消
COMMIT; -- 確定する場合
-- ROLLBACK; -- 取り消す場合
2. 事前にSELECTで対象行を確認する
事前確認のパターン
-- Step 1: まずSELECTで対象を確認
SELECT id, name, department, salary
FROM employees
WHERE department = '営業' AND salary < 300000;
-- Step 2: 問題なければUPDATEを実行(WHEREは同じ条件)
UPDATE employees
SET salary = 300000
WHERE department = '営業' AND salary < 300000;
3. LIMITでテスト実行する(MySQL限定)
LIMITでテスト(MySQL)
-- まず1件だけ更新して結果を確認
UPDATE employees
SET salary = salary * 1.1
WHERE department = '開発'
LIMIT 1;
-- 結果を確認して問題なければ全件実行
SELECT * FROM employees WHERE department = '開発';
注意:LIMITはMySQL固有の機能です。PostgreSQL・SQL Server・Oracleでは使用できません。
安全なUPDATE実行チェックリスト
| チェック項目 |
内容 |
| WHERE句の確認 |
WHERE句が正しいか、漏れがないか確認する |
| SELECTで事前確認 |
同じWHERE条件でSELECTし、対象行を確認する |
| トランザクション |
BEGIN〜COMMIT/ROLLBACKで囲んで実行する |
| バックアップ |
大量更新前にテーブルのバックアップを取得する |
| 影響行数の確認 |
更新後の Rows affected が想定通りか確認する |
よくあるエラーと対処法
| エラー内容 |
原因 |
対処法 |
| WHERE句の付け忘れ |
全レコードが意図せず更新される |
実行前に必ずSELECTで確認。BEGINで囲む |
| 型の不一致 |
数値カラムに文字列を設定 |
カラムの型を確認し、適切な値を指定 |
| NOT NULL制約違反 |
NOT NULLカラムにNULLを設定 |
制約を確認し、NULLではなくデフォルト値を使用 |
| 外部キー制約違反 |
参照先に存在しない値を設定 |
参照先テーブルにデータが存在するか確認 |
| サブクエリが複数行を返す |
SET col = (SELECT …) で2行以上返る |
WHERE条件を追加するか、集計関数(MAX, MIN等)を使用 |
| UNIQUE制約違反 |
一意制約のあるカラムに重複値を設定 |
更新後に重複が発生しないか事前にSELECTで確認 |
| デッドロック |
複数トランザクションが互いにロック待ち |
更新順序を統一し、トランザクションを短くする |
RDBMS別のUPDATE構文の違い
基本的なUPDATE文の構文はどのRDBMSでも同じですが、JOINを使った更新や一部の機能に違いがあります。
| 機能 |
MySQL |
PostgreSQL |
SQL Server |
Oracle |
| 基本構文 |
UPDATE SET WHERE |
UPDATE SET WHERE |
UPDATE SET WHERE |
UPDATE SET WHERE |
| JOIN更新 |
UPDATE … JOIN … SET |
UPDATE … SET … FROM |
UPDATE … SET … FROM … JOIN |
MERGE INTO … USING |
| LIMIT |
LIMIT n |
非対応(CTEで代替) |
TOP n |
ROWNUM |
| RETURNING句 |
非対応 |
RETURNING * |
OUTPUT句 |
RETURNING INTO |
| CASE WHEN |
対応 |
対応 |
対応 |
対応 |
| トランザクション |
BEGIN / COMMIT |
BEGIN / COMMIT |
BEGIN TRAN / COMMIT |
自動(COMMIT必須) |
まとめ
| 更新パターン |
SQL |
用途 |
| 全レコード更新 |
UPDATE t SET col = val |
一括リセット・一律変更 |
| 条件付き更新 |
UPDATE t SET col = val WHERE ... |
特定行だけを変更 |
| 複数カラム更新 |
SET col1 = val1, col2 = val2 |
一度に複数項目を変更 |
| CASE WHEN |
SET col = CASE WHEN ... END |
行ごとに異なる値を設定 |
| サブクエリ |
SET col = (SELECT ...) |
別テーブルの値を参照して更新 |
| JOIN更新 |
UPDATE ... JOIN ... SET |
結合した結果で更新(MySQL) |
| NULL設定 |
SET col = NULL |
値をNULLにクリア |
| NULL回避 |
COALESCE(val, default) |
NULLの場合にデフォルト値を使用 |
UPDATE文はSQLの中でも影響範囲が大きい操作です。WHERE句の指定漏れで全行を意図せず更新してしまう事故は、現場でもよく発生します。必ずSELECTで事前確認し、トランザクション内で実行することを習慣にしましょう。
関連記事