「社員の名前を直したい」「部署名をまとめて変えたい」。そんなときに使うのがSQLのUPDATE文です。SETで「何を変えるか」、WHEREで「どの行を変えるか」を決めます。まずは1人の名前を変える例から見ていきましょう。

実行前にここだけ確認
WHEREを省略すると全行が更新対象になります。 実行前に同じ条件のSELECTで対象を確認しましょう。この記事の実行例はSQL Server LocalDB+SSMS向けです。

UPDATE文の基本構文:SETとWHEREの役割

UPDATE テーブル名
SET 列名 = 新しい値
WHERE 更新条件;

例えば「社員IDが1の氏名だけを変更する」なら、次のように書きます。まだ練習用テーブルがない場合は、後の準備手順から始めてください。

UPDATE dbo.Employees
SET EmployeeName = N'山田一郎'
WHERE EmployeeId = 1;
図解:WHEREで行を選び、SETで値を変更
更新前|社員ID 1山田太郎部署:営業部
更新後|社員ID 1山田一郎部署:営業部(変更なし)
WHERE:EmployeeId = 1 → ID 1の行だけ
SET:EmployeeName → 氏名の列だけ
ID 2~4の行はそのままです。図は架空データによる説明用で、実際の操作画面ではありません。
句決めることこの例
UPDATEどのテーブルかdbo.Employees
SETどの列を何に変えるかEmployeeNameを山田一郎へ
WHEREどの行を変えるかEmployeeIdが1の行

UPDATEで変えられるのは、すでにある行の値です。行の追加はINSERT、行の削除はDELETEを使います。UPDATEで列そのものを増やすわけではありません。

複数列の更新と複数行の更新は別の操作

図解:「横の項目」と「縦の件数」を分ける
複数列を更新社員ID 2の1人について
部署・年齢・給与をまとめて変更

SETをカンマで区切る
対象はWHEREで1行に限定
複数行を更新営業部の2人について
同じ部署名の変更を適用

WHEREに一致する行すべてが対象
1文=1行とは限らない

ここは少し混同しやすいところです。1人の「部署と給与」を変えるのは複数列の更新。「営業部の全員」を変えるのは複数行の更新です。どの項目を変えるのかと、誰を対象にするのかを分けて考えると整理しやすくなります。もちろん、両方を同時に指定することもできます。

SQL Server+SSMSで練習用データを準備する

本番データでは試さない

ここからは練習用のデータベースを用意して進めます。SqlPracticeDBやEmployeesがすでにある場合は、何に使っているか確認し、削除・上書きは避けてください。別名のDBを作る場合は、後に出てくるUSEの名前も合わせます。

Windows 11、SQL Server LocalDB、SSMSを使う前提です。接続先は (LocalDB)\MSSQLLocalDB。未設定の方はLocalDBとSSMSの接続手順を先に確認してください。画面の配置はバージョンによって異なります。

1.データベースとテーブルを作成

SSMSで「新しいクエリ」を開き、次を実行します。GOはSSMSなどが解釈するバッチ区切りで、SQL文そのものではありません。C#から実行するときはGOを送らず、処理を分けます。

CREATE DATABASE SqlPracticeDB;
GO
USE SqlPracticeDB;
GO

CREATE TABLE dbo.Employees
(
    EmployeeId INT PRIMARY KEY,
    EmployeeName NVARCHAR(50) NOT NULL,
    Department NVARCHAR(50) NOT NULL,
    Age INT NOT NULL,
    Salary INT NOT NULL
);

社員IDを主キーにし、日本語の氏名・部署はNVARCHARで保持します。ここで使う社員名・年齢・給与はすべて説明用の架空データです。

2.4行の初期データを登録

INSERT INTO dbo.Employees
    (EmployeeId, EmployeeName, Department, Age, Salary)
VALUES
    (1, N'山田太郎', N'営業部', 28, 300000),
    (2, N'佐藤花子', N'開発部', 32, 380000),
    (3, N'鈴木一郎', N'営業部', 40, 450000),
    (4, N'高橋美咲', N'総務部', 25, 280000);

SELECT * FROM dbo.Employees ORDER BY EmployeeId;
ID・氏名部署年齢給与
1 山田太郎営業部28300000
2 佐藤花子開発部32380000
3 鈴木一郎営業部40450000
4 高橋美咲総務部25280000

SQL ServerのUnicode文字列はN付きのシングルクォートで記述します。上の表は初期データの想定結果です。CREATE TABLEとINSERTは初回だけ実行してください。同じIDを再登録すると主キー重複のエラーになります。

UPDATEの実践:1行・複数列・複数行を更新

準備ができたら、例1~5を同じ練習用DBで上から順に1回ずつ試してみましょう。SSMSでは選択した範囲だけを実行できます。まず先頭のSELECTで対象を見て、問題なければUPDATE、その後にもう一度SELECTで結果を見る、という順番です。SELECTの書き方を確認したい方はSELECT文の使い方も参考にしてください。

例1:WHEREで特定の1行を更新する

まずはID 1の人だけ、名前を変えてみましょう。対象を決めるのは主キーのEmployeeIdです。部署・年齢・給与は変えません。冒頭の例をすでに実行していれば、同じ名前をもう一度設定することになります。

-- まず、このSELECTだけを実行して対象を確認
SELECT * FROM dbo.Employees WHERE EmployeeId = 1;

-- 対象が正しければ更新
UPDATE dbo.Employees
SET EmployeeName = N'山田一郎'
WHERE EmployeeId = 1;

-- UPDATEの直後に件数、続いて結果を確認
SELECT @@ROWCOUNT AS UpdatedRows;
SELECT * FROM dbo.Employees WHERE EmployeeId = 1;

確認するのは、UpdatedRowsが1になり、氏名が山田一郎に変わっているかどうかです。@@ROWCOUNTが返すのは直前の文の影響行数なので、UPDATEとの間に別のSELECTやPRINTを挟むと、見たい件数ではなくなってしまいます。同じ値を設定した行も数えるため、「実際に値が変わった件数」とは限らない点にも注意してください。

例2:複数カラムをカンマで区切って更新する

次はID 2の部署・年齢・給与をまとめて変えます。SETを何度も書く必要はありません。変更したい列をカンマでつなげれば大丈夫です。最後の列の後にはカンマを付けないようにしましょう。

SELECT * FROM dbo.Employees WHERE EmployeeId = 2;

UPDATE dbo.Employees
SET Department = N'企画部',
    Age = 33,
    Salary = 400000
WHERE EmployeeId = 2;

SELECT * FROM dbo.Employees WHERE EmployeeId = 2;
ID 2の項目更新前更新後
部署開発部企画部
年齢3233
給与380000400000

例3:条件に一致する複数行をまとめて更新する

今度は営業部の2人を、まとめて営業企画部へ変更します。ここで気を付けたいのは、最後のSELECTです。更新後には「営業部」という名前では見つからなくなるので、「営業企画部」で確認します。

SELECT * FROM dbo.Employees
WHERE Department = N'営業部';

UPDATE dbo.Employees
SET Department = N'営業企画部'
WHERE Department = N'営業部';

SELECT * FROM dbo.Employees
WHERE Department = N'営業企画部';

この例では、ID 1・3の2行が更新対象です。特定のIDを複数指定するなら、WHERE EmployeeId IN (1, 3) という条件でも絞れます。

例4:現在の値に加算して更新する

SELECT EmployeeId, Salary FROM dbo.Employees
WHERE Department = N'営業企画部';

UPDATE dbo.Employees
SET Salary = Salary + 10000
WHERE Department = N'営業企画部';

SELECT EmployeeId, Salary FROM dbo.Employees
WHERE Department = N'営業企画部';

1回実行した場合、ID 1は300000→310000、ID 3は450000→460000になります。右辺のSalaryは更新前の値です。ここは名前の変更とは違い、もう一度実行すると、さらに10000増えてしまいます。 結果を見直すときは、最後のSELECTだけを実行しましょう。

例5:AND・ORで更新条件を組み合わせる

営業企画部かつ40歳以上のID 3だけ、給与を20000増やします。ANDは両方の条件を満たす行、ORはどちらかを満たす行を対象にします。混在させるときは括弧で意図を明確にします。

SELECT EmployeeId, Age, Salary FROM dbo.Employees
WHERE Department = N'営業企画部' AND Age >= 40;

UPDATE dbo.Employees
SET Salary = Salary + 20000
WHERE Department = N'営業企画部' AND Age >= 40;

SELECT EmployeeId, Age, Salary FROM dbo.Employees
WHERE Department = N'営業企画部' AND Age >= 40;

例4まで進めていれば、ID 3の給与は460000→480000になります。例えば「営業部または開発部、かつ40歳以上」なら、部署のOR条件全体を括弧で囲み、その外側で年齢の条件をANDで結びます。

練習後の結果を一覧で確認

ID氏名・部署年齢給与
1山田一郎・営業企画部28310000
2佐藤花子・企画部33400000
3鈴木一郎・営業企画部40480000
4高橋美咲・総務部25280000

例1~5を各1回実行した場合の想定結果です。順番を変えたり加算を繰り返したりすると結果が異なります。

全件更新とROLLBACK:取り消せる条件を知る

WHEREなしはエラーにならない

WHEREを省略したUPDATEは全行を対象にします。自動コミットで確定した更新は、後からROLLBACKを書いても取り消せません。 SQL Serverは既定では自動コミットで動作します。取り消しを練習する場合は、更新前に明示的なトランザクションを開始します。

図解:対象確認 → 更新 → 確認して終了
1 対象を確認接続先・DB・WHERE条件・想定件数を確認
2 更新するBEGIN TRANSACTION
→ UPDATE
3 結果を確認更新件数と値を確認し、どちらかで終了
内容が正しい → COMMIT
変更を確定する
取り消す → ROLLBACK
未確定の変更を戻す
確認が終わったら、COMMITかROLLBACKで必ず終了します。同時更新やエラーへの備えは、この手順とは別に必要です。

次は全行の給与を一時的に300000にし、同じコード内で取り消す練習です。未完了のトランザクションがない、練習用の新しいクエリ接続で実行してください。

USE SqlPracticeDB;
GO

BEGIN TRANSACTION;

UPDATE dbo.Employees
SET Salary = 300000; -- 練習用:全行が対象

SELECT @@ROWCOUNT AS UpdatedRows;
SELECT EmployeeId, Salary FROM dbo.Employees ORDER BY EmployeeId;

ROLLBACK TRANSACTION; -- この例では必ず取り消す

SELECT EmployeeId, Salary FROM dbo.Employees ORDER BY EmployeeId;

最初の結果では給与が全員300000になり、ROLLBACK後の結果では実行前の給与に戻る想定です。例1~5の後なら、最後の一覧は310000・400000・480000・280000になります。

変更を残したい場合は、同じ接続で結果を確認してからCOMMITを実行します。取り消すならROLLBACKです。両方を順番に実行するわけではありません。途中でエラーになってもトランザクションが残る場合があるので、終了しているかを確認し、必要なら取り消してください。

トランザクションを開いたまま席を離れると、ロックで他の処理を待たせる場合があります。本番ではバックアップ・実行権限・同時更新・エラー処理も含めて設計してください。詳しくはROLLBACKの使い方とCOMMITの使い方を参照してください。

応用:行ごとに別の値を設定するCASE

ID 1と3で異なる給与を設定する例です。WHEREで対象を絞り、CASEで行ごとの設定値を分けます。練習後のデータを残せるよう、この例も最後にROLLBACKします。

BEGIN TRANSACTION;

UPDATE dbo.Employees
SET Salary = CASE EmployeeId
    WHEN 1 THEN 320000
    WHEN 3 THEN 490000
    ELSE Salary
END
WHERE EmployeeId IN (1, 3);

SELECT EmployeeId, Salary FROM dbo.Employees
WHERE EmployeeId IN (1, 3);

ROLLBACK TRANSACTION;

CASEは「どの値にするか」を分けるもので、対象の行を絞る役目はWHEREです。また、ELSEを省略すると、どの条件にも当てはまらない場合はNULLになります。この例ではELSE Salaryとして、元の給与を残す形にしています。

更新できない・0件になるときの確認表

現象まず確認すること
0行更新同じWHERE条件でSELECT。前の例で部署名を変えていないか、接続先DBが正しいかを確認。
全行・想定以上の行が更新WHEREの省略、ORの括弧、条件の広さを確認。未確定なら同じ接続でROLLBACK。確定後は管理者と復旧手順を検討。
Invalid object nameDB・スキーマ・テーブル名を確認。練習例はSqlPracticeDBのdbo.Employees。
Invalid column name列名の綴りを確認。テーブル名ではなく列名をSETに書く。
Conversion failed数値列に文字を渡していないか、値と列の型を確認。
Cannot insert the value NULLNOT NULL列にはNULLを設定できない。エラー回避だけのために制約を外さず、設計に合う値を使う。
処理が長く終わらない別接続のトランザクション、ロック待ち、対象件数を確認。原因不明のまま繰り返し実行しない。
権限エラー対象へのUPDATE権限などを確認。必要な権限は管理者に相談。

NULLは「= NULL」ではなく「IS NULL」で判定

NULLを含む行の検索にはIS NULLを使います。NULLを設定する際も、文字列の「’NULL’」とは区別します。本記事のEmployeesは全列NOT NULLなので、NULLの更新例をそのまま当てはめないでください。

目的書き方の考え方
NULLの行を対象にするWHERE 対象列 IS NULL
NULLでない行を対象にするWHERE 対象列 IS NOT NULL
値をNULLにするSET 対象列 = NULL(NULL許可列のみ)

よくある質問

別テーブルの値を使って更新できますか?

できます。SQL ServerならUPDATE…FROMやサブクエリを使います。ただし、JOINを使う書き方はDB製品によって違います。また、更新する1行に参照元の複数行が対応すると、どの値が使われるか決まらない場合があります。先にSELECTで結合結果を見て、1行に絞れているか確認しておくと安心です。

MySQL・PostgreSQLでも同じコードを使えますか?

単純なUPDATE・SET・WHEREの考え方は共通ですが、本記事のN付き文字列、dbo、GO、@@ROWCOUNT、トランザクション例はSQL Server向けです。他のDBへはそのまま貼り付けず、各製品の構文を確認してください。

UPDATE後にROLLBACKすれば必ず元に戻せますか?

いいえ。ROLLBACKで取り消せるのは、まだ確定していないトランザクション内の変更です。自動コミットやCOMMITで確定した変更を、通常のROLLBACKで戻すことはできません。

まとめ:実行前の対象確認と実行後の件数確認

まずは「SETで何を変えるか、WHEREでどの行を変えるか」を押さえれば大丈夫です。実行前にSELECTで対象を確認し、更新後に件数と値を見直す。このひと手間を習慣にしておくと、意図しない更新に気付きやすくなります。慣れてきたら、複数列の更新やCASEの例も試してみてください。

参考:SQL Server公式資料

UPDATEの構文 / @@ROWCOUNT / トランザクション / CASE式

図・表は架空のデータによる説明用です。結果は公式資料とコードをもとにした想定で、SQL Server・SSMSでの実行確認はしていません。