登録済みのデータを変更する UPDATE と、削除する DELETE を学びます。どちらも、第6章で学んだ WHERE 句で対象の行を指定します。WHERE を書き忘れるとテーブルの全行が変わってしまうこと、ROLLBACK で元に戻せるのは COMMIT の前だけであることを、実際に試しながら身に付けます。この章の練習は、最後に社員10人・部署4件のデータに戻るように進めます。
この章で学ぶこと
UPDATE テーブル名 SET 列名 = 値 WHERE 条件DELETE FROM テーブル名 WHERE 条件- WHERE を書き忘れたときに何が起きるか、
ROLLBACKでの戻し方 - 変更・削除でも制約が働くこと(外部キーで参照されている行は消せない)
7.1 データを変更する:UPDATE
UPDATE は、テーブルの中の行の 列の値を変える SQL 文です。第1章で学んだ CRUD の U(Update:変更) にあたります。次の形で書きます。
UPDATE テーブル名
SET 列名1 = 値1, 列名2 = 値2, ...
WHERE 条件;
-
SETの後ろに、「どの列をどの値に変えるか」を列名 = 値の形で書きます。複数の列を変えるときは,で区切ります -
WHEREの後ろに、「どの行を変えるか」の条件を書きます。書き方は SELECT の WHERE と同じです。1行だけを変えるときは、主キーで指定します
雷禅さん(社員ID 1)の年齢を 27 に変えてみましょう。1つずつ Ctrl + Enter で実行します。
UPDATE EMPLOYEE SET AGE = 27 WHERE EMP_ID = 1;
「スクリプト出力」に「1行更新しました。」と表示されます。SELECT で確認します。
SELECT EMP_ID, NAME, AGE FROM EMPLOYEE WHERE EMP_ID = 1;
| EMP_ID | NAME | AGE |
|---|---|---|
| 1 | 雷禅 海皇 | 27 |

図7-1 UPDATE と SELECT を F5 でまとめて実行した場合のスクリプト出力(まだ COMMIT していない)
この変更はまだ確定していません(第4章)。ここでは ROLLBACK で元に戻します。
ROLLBACK;
もう一度 SELECT すると、AGE は 26 に戻っています。
複数の列をまとめて変える
年齢と住所を同時に変えます。
UPDATE EMPLOYEE SET AGE = 27, ADDRESS = '神奈川県' WHERE EMP_ID = 1;
SELECT EMP_ID, NAME, AGE, ADDRESS FROM EMPLOYEE WHERE EMP_ID = 1;
| EMP_ID | NAME | AGE | ADDRESS |
|---|---|---|---|
| 1 | 雷禅 海皇 | 27 | 神奈川県 |
確認したら ROLLBACK; で戻します。
元の値を使って変える
SET の値には、計算式も書けます。開発部(部署ID 3)の社員の年齢を、全員1つ増やします。
UPDATE EMPLOYEE SET AGE = AGE + 1 WHERE DEPT_ID = 3;
「4行更新しました。」と表示されます。WHERE の条件に合う行が複数あれば、その すべて が変わります。
SELECT NAME, AGE FROM EMPLOYEE WHERE DEPT_ID = 3 ORDER BY EMP_ID;
| NAME | AGE |
|---|---|
| 林檎 星飛 | 25 |
| 田中 美咲 | 25 |
| 高橋 翔 | 36 |
| 中村 結衣 | 27 |
AGE = AGE + 1 は、「変更前の AGE の値に 1 を足したものを、新しい AGE の値にする」という意味です。確認したら ROLLBACK; で戻します。
【知識メモ】条件に合う行が無いとき
UPDATE EMPLOYEE SET AGE = 27 WHERE EMP_ID = 999; のように、条件に合う行が無い UPDATE は、エラーにならず「0行更新しました。」と表示されます。「何行更新しました」の数は、意図した行数と合っているかを確かめる手がかりになるので、必ず見る習慣をつけましょう。
7.2 WHERE を忘れると全行が変わる
UPDATE の WHERE 句は省略できます。省略すると、テーブルのすべての行 が変わります。わざと試してみましょう。
UPDATE EMPLOYEE SET AGE = 30;
「10行更新しました。」と表示されます。
SELECT NAME, AGE FROM EMPLOYEE ORDER BY EMP_ID;
| NAME | AGE |
|---|---|
| 雷禅 海皇 | 30 |
| 院照 心愛 | 30 |
| 林檎 星飛 | 30 |
| 田中 美咲 | 30 |
| 佐藤 健太 | 30 |
| 鈴木 花子 | 30 |
| 高橋 翔 | 30 |
| 伊藤 さくら | 30 |
| 渡辺 大輔 | 30 |
| 中村 結衣 | 30 |
全員の年齢が 30 になってしまいました。まだ COMMIT していないので、ROLLBACK; で元に戻せます。実行して、SELECT で年齢が元に戻ったことを確認してください。
【再確認】UPDATE・DELETE は、WHERE を先に書く
もしこの状態で COMMIT していたら、ROLLBACK では戻せません。全員の元の年齢を調べ直して1人ずつ UPDATE し直すしかなく、調べる手段が無ければデータは失われます。業務のデータベースでこれをやると、重大な事故になります。
UPDATE や DELETE を書くときは、先に WHERE 句から書いて、最後に UPDATE … SET や DELETE FROM を書く 習慣をつけると、書き忘れを防げます。実行の前には、同じ WHERE 句を付けた SELECT で、対象の行が意図したものだけになっているかを確かめます(7.6)。
7.3 変更でも制約は働く
第3章の制約は、INSERT だけでなく UPDATE でも働きます。次の3つはすべてエラーになり、変更されません。
-- 性別に 3 は入れられない(CHECK 制約)
UPDATE EMPLOYEE SET GENDER = 3 WHERE EMP_ID = 1;
ORA-02290: チェック制約(DBAPP.CK_EMPLOYEE_GENDER)に違反しました
-- 部署ID 9 の部署は無い(外部キー制約)
UPDATE EMPLOYEE SET DEPT_ID = 9 WHERE EMP_ID = 1;
ORA-02291: 整合性制約(DBAPP.FK_EMPLOYEE_DEPARTMENT)に違反しました - 親キーがありません
-- 年齢は NOT NULL
UPDATE EMPLOYEE SET AGE = NULL WHERE EMP_ID = 1;
ORA-01407: ("DBAPP"."EMPLOYEE"."AGE")をNULLには更新できません。
制約のおかげで、UPDATE で誤った値を入れてしまうことも防げます。
7.4 データを削除する:DELETE
DELETE は、テーブルから 行を削除する SQL 文です。CRUD の D(Delete:削除) にあたります。これで、CRUD の4つの SQL 文がすべてそろいました。次の形で書きます。
DELETE FROM テーブル名 WHERE 条件;
行ごと消すので、列名は書きません。WHERE で「どの行を消すか」を指定します。UPDATE と同じく、WHERE を省略するとすべての行が消えます。
社員を1人追加して、削除する
削除の練習のために、社員を1人追加してから削除します。今回は、INSERT を COMMIT で確定 し、その後の DELETE も COMMIT して、確定した変更の流れを確かめます。
-
山田 太郎さんを総務部に登録し、COMMIT します。 2つの文を選択して Ctrl + Enter を押すか、F5 で実行します。
ワークシート(XE_DBAPP)INSERT INTO EMPLOYEE (EMP_ID, NAME, GENDER, AGE, BIRTH_DATE, DEPT_ID, ADDRESS) VALUES (SEQ_EMP.NEXTVAL, '山田 太郎', 1, 30, DATE '1996-01-01', 1, '東京都'); COMMIT; -
登録されたことを確認します。
ワークシート(XE_DBAPP)SELECT EMP_ID, NAME, DEPT_ID FROM EMPLOYEE WHERE NAME = '山田 太郎';EMP_ID NAME DEPT_ID 13 山田 太郎 1 社員IDは 11 ではなく 13 になります。第4章 4.5 でエラーになった2回の INSERT が、シーケンスの 11 と 12 を消費したためです。第4章の練習を省いた場合や、作り直した場合は、別の番号になります。番号が違っていても問題ありません。
-
山田さんを削除します。社員IDが環境によって違うので、ここでは氏名で指定します。 「1行削除しました。」と表示されます。同じ SELECT を実行すると、結果は0行になっています。
ワークシート(XE_DBAPP)DELETE FROM EMPLOYEE WHERE NAME = '山田 太郎'; -
COMMIT して削除を確定します。
ワークシート(XE_DBAPP)COMMIT; -
社員が10人に戻っていることを確認します。
ワークシート(XE_DBAPP)SELECT EMP_ID, NAME FROM EMPLOYEE ORDER BY EMP_ID;
【知識メモ】現場では主キーで指定する
この練習では、社員IDが環境によって違うため氏名で指定しましたが、業務のシステムでは、変更・削除の対象は 主キー(WHERE EMP_ID = 13)で指定するのが原則です。氏名は同じ値の人が2人以上いる可能性があり、意図しない行まで消してしまうおそれがあるからです。Spring入門の社員管理アプリも、削除や変更は社員IDで行います。
すべての行を削除する
WHERE を省略した DELETE も試してみましょう。もちろん、この後 ROLLBACK します。
DELETE FROM EMPLOYEE;
「10行削除しました。」と表示されます。SELECT * FROM EMPLOYEE; を実行すると、結果は0行です。テーブル自体は残っていて、中身だけが空になっています(DROP TABLE との違いです)。
ROLLBACK;
ROLLBACK で10人が戻ります。SELECT で確認してください。
7.5 外部キーで参照されている行は消せない
営業部(部署ID 2)を部署テーブルから削除しようとしてみます。
DELETE FROM DEPARTMENT WHERE DEPT_ID = 2;
ORA-02292: 整合性制約(DBAPP.FK_EMPLOYEE_DEPARTMENT)に違反しました - 子レコードがあります
営業部には4人の社員が所属しています。営業部を消すと、その4人の DEPT_ID が参照先の無い値になってしまうので、外部キー制約がこの削除を拒否しました。「子レコードがあります」は、「この行を参照している行(社員)がある」という意味です。
一方、社員がいない人事部(部署ID 4)は削除できます。
DELETE FROM DEPARTMENT WHERE DEPT_ID = 4;
「1行削除しました。」と表示されます。人事部は第10章で使うので、ROLLBACK; で戻しておきます。SELECT * FROM DEPARTMENT ORDER BY DEPT_ID; で、4件に戻っていることを確認してください。
【知識メモ】参照されている行を消したいときは
営業部を本当に消したいなら、先に営業部の社員を別の部署に UPDATE するか DELETE してから、営業部を消します。参照している側(子)を先に片付けてから、参照されている側(親)を消す、という順番は、第3章の DROP TABLE の順番と同じ考え方です。
7.6 現場での変更・削除の進め方
UPDATE と DELETE は、一度 COMMIT すると戻せない操作です。業務のデータベースで手作業で実行するときは、次の手順で進めるのが基本です。
-
同じ WHERE 句で SELECT する:
SELECT * FROM EMPLOYEE WHERE EMP_ID = 13;のように、変更・削除する行だけが表示されることを確かめます - UPDATE・DELETE を実行する:「何行更新しました/削除しました」の数が、1 で確かめた行数と同じであることを確かめます
- もう一度 SELECT する:変更後の値が意図どおりか確かめます
- COMMIT する:問題があれば、COMMIT の代わりに ROLLBACK します
この教材の後半も、この手順で進めます。Spring入門で作る社員管理アプリでは、この一連の流れをプログラムが行います。
7.7 うまくいかないときは
| 症状 | 考えられる原因と対処 |
|---|---|
| 「0行更新しました。」「0行削除しました。」 | WHERE の条件に合う行がありません。条件の値(ID、氏名の空白など)を確認してください。同じ WHERE 句で SELECT すると確かめられます。 |
| 想定より多くの行が「更新しました」と表示された | WHERE の条件が広すぎるか、WHERE を書き忘れています。COMMIT する前なら ROLLBACK; で戻してください。 |
| 「ORA-02292: … 子レコードがあります」 | 消そうとした行が、別のテーブルの外部キーから参照されています。参照している側の行を先に変更・削除してください。 |
| 「ORA-02290」「ORA-02291」「ORA-01407」 | UPDATE で制約に反する値を入れようとしています。7.3 を参照してください。 |
| 「ORA-00936: 式がありません。」 |
WHERE EMP_ID == 1 のように = を2つ書いているか、SET の値が抜けています。 |
| 「ORA-00933: SQLコマンドが正しく終了されていません。」 |
UPDATE・SET・WHERE の順番が違うか、文字の値を ' で囲んでいません。 |
| ROLLBACK しても元に戻らない | すでに COMMIT されています。SQL Developer の自動コミットの設定が有効になっていないか、ツール → プリファレンス → データベース → ワークシート の「SQLワークシートでの自動コミット」を確認してください(既定では無効です)。 |
ほかのエラーは、付録B「よくあるエラーと対処法」 も参考にしてください。
7.8 まとめと確認問題
まとめ
-
UPDATE テーブル名 SET 列名 = 値, … WHERE 条件;で、条件に合う行の列の値を変える。SET AGE = AGE + 1のように元の値を使える -
DELETE FROM テーブル名 WHERE 条件;で、条件に合う行を消す - WHERE を省略すると すべての行 が対象になる。WHERE 句から先に書き、実行前に同じ WHERE 句の SELECT で対象を確かめる
- COMMIT する前なら ROLLBACK で戻せる。COMMIT した後は戻せない
- UPDATE でも制約(CHECK・外部キー・NOT NULL)は働く。外部キーで参照されている行は DELETE できない(ORA-02292)
この章で使った SQL は、付録C「SQL 早見表」 にまとめています。
確認問題
問1 社員ID 2 の院照さんの住所を「滋賀県」に変える SQL を書いてください。
解答を見る
UPDATE EMPLOYEE SET ADDRESS = '滋賀県' WHERE EMP_ID = 2;
試したら、ROLLBACK; で戻しておきましょう。
問2 UPDATE EMPLOYEE SET ADDRESS = '東京都'; を実行すると、何が起きますか。
解答を見る
WHERE が無いので、社員テーブルの全10行の住所が「東京都」になります。COMMIT する前なら ROLLBACK で戻せます。
問3 UPDATE を実行したところ「0行更新しました。」と表示されました。考えられる原因は何ですか。
解答を見る
WHERE の条件に合う行が無かったことです。ID の値や、文字の値(空白の有無など)が間違っていないかを確認します。同じ WHERE 句で SELECT すると確かめられます。
問4 DELETE FROM DEPARTMENT WHERE DEPT_ID = 3; がエラーになる理由と、エラー番号を答えてください。
解答を見る
開発部(部署ID 3)には4人の社員が所属していて、外部キーで参照されているためです。「ORA-02292: 整合性制約(DBAPP.FK_EMPLOYEE_DEPARTMENT)に違反しました - 子レコードがあります」になります。
問5 業務のデータベースで DELETE を実行する前に、まず何をするべきですか。
解答を見る
同じ WHERE 句を付けた SELECT を実行して、削除される行が意図したものだけであることを確かめます。実行後は「何行削除しました」の数を確かめてから COMMIT します。