こんにちは、かつコーチです。
前回はUPDATE文で既存データを書き換える方法を解説しました。
DML(データ操作言語)の最後のピースが、テーブルから不要な行を取り除くDELETE文です。
DELETE文はSELECT・INSERT・UPDATEに比べて操作が単純に見える反面、条件指定を1つ間違えるとデータを取り返しのつかない形で失う、もっとも事故が起きやすい文でもあります。
今回は基本の書き方に加えて、私が実際にやりがちなミスとその防ぎ方まで踏み込んで解説します。
DELETE文とは?
テーブルから行を削除するSQL文
DELETE文とは、テーブルから条件に合致した行(レコード)を削除するためのSQL文です。
INSERT文が行を「追加」し、UPDATE文が行を「書き換える」のに対して、DELETE文は行そのものを「取り除く」操作を担当します。
削除の単位はあくまで「行」であり、特定の列だけを消すような操作はできません。
特定の列の値を消したい場合は、DELETE文ではなくUPDATE文でNULLを代入するのが正しい方法です。
なぜDELETE文が必要なのか
退会したユーザーの情報を削除したり、キャンセルされた注文データを取り除いたりと、Webアプリの運用では不要になったデータを整理する場面が必ず出てきます。
データを溜め続けるだけでは、テーブルが肥大化して検索が遅くなったり、個人情報保護の観点で問題になったりすることもあります。
DELETE文は、こうした「もう不要になったデータ」をテーブルから正しく取り除くための唯一の手段です。
基本の書き方
この記事では、以下のテーブルを使います。
CREATE TABLE customers (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(50) NOT NULL,
email VARCHAR(100) NOT NULL,
status VARCHAR(20) DEFAULT '有効',
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
手順1:WHERE句で条件を指定して削除する
もっとも基本的な書き方は、WHERE句で削除対象を絞り込む方法です。
DELETE FROM customers WHERE id = 5;
idが5の行だけがテーブルから削除されます。
WHERE句に一致する行が複数あれば、該当する行すべてが削除される点はUPDATE文と同じです。
手順2:複数条件を組み合わせて削除する
AND・ORを使って、複数の条件を組み合わせることもできます。
DELETE FROM customers WHERE status = '退会済み' AND created_at < '2024-01-01';
「退会済みで、かつ2024年より前に登録された顧客」だけを削除対象にできます。
条件が複雑になるほど、意図しない行まで削除してしまうリスクが上がるため、実行前の確認がより重要になります。
手順3:削除前にSELECT文で対象を確認する
DELETE文を実行する前に、同じ条件でSELECT文を実行して対象行を確認するのが実務での基本動作です。
-- まずSELECTで対象を確認する
SELECT * FROM customers WHERE status = '退会済み' AND created_at < '2024-01-01';
-- 件数・内容に問題なければDELETEに切り替える
DELETE FROM customers WHERE status = '退会済み' AND created_at < '2024-01-01';
WHERE句をそのままSELECT文に流用できるので、「削除する前に必ず同じ条件でSELECTする」という手順を習慣化しておくと、事故を大きく減らせます。
よくあるつまずきポイント・エラー対処
WHERE句を忘れて全件削除してしまう
❌ Before:WHERE句を書き忘れて実行してしまう
DELETE FROM customers;
このSQL文は、customersテーブルのすべての行を削除します。
エラーにはならず、静かに全件が消えるところがこの操作のもっとも怖い点です。
私自身、開発環境でテストデータを整理しようとした際に、WHERE句を書く前にうっかりEnterキーを押してしまい、数百件のダミーデータを一瞬で失った経験があります。
幸い開発環境だったため実害はありませんでしたが、これが本番環境だったらと思うと今でも背筋が冷えます。
✅ After:DELETE文を書くときはWHERE句から先に確定させる
-- WHERE句を先に書いてから、DELETE FROMを書き足す癖をつける
WHERE id = 5;
-- ↓ 頭にDELETE FROM customersを付け足す
DELETE FROM customers WHERE id = 5;
「DELETE FROMから書き始めない」「WHERE句を先に確定させてから文を組み立てる」というルールを自分に課しておくと、うっかりミスを大きく減らせます。
また可能であれば、開発時はSQLクライアントの自動コミットをオフにし、トランザクション内で確認してから確定する運用にしておくと、より安全です。
外部キー制約でエラーになる
❌ Before:関連テーブルにデータが残ったまま親テーブルの行を削除しようとする
DELETE FROM customers WHERE id = 3;
ordersテーブルがcustomer_idでcustomers.idを参照する外部キー制約を持っている場合、customers側に紐づく注文データが残っていると、次のようなエラーになります。
ERROR 1451 (23000): Cannot delete or update a parent row: a foreign key constraint fails
親のデータだけを消そうとしても、子のデータが参照している限り、データベースが整合性を守るために削除を拒否してくれます。
✅ After:子テーブルのデータから先に削除するか、削除の順序を設計する
-- 先に関連する注文データを削除する
DELETE FROM orders WHERE customer_id = 3;
-- その後で顧客データを削除する
DELETE FROM customers WHERE id = 3;
このエラーは一見面倒に思えますが、「関連データが残ったまま親を消してしまう」という、より深刻なデータ不整合を未然に防いでくれるありがたい仕組みです。
削除の順序は、テーブル間の依存関係を整理したうえで設計しておく必要があります。
応用・一歩先の使い方
テーブルを空にするTRUNCATE文との違い
テーブルの中身を全件削除したいだけであれば、TRUNCATE TABLEという別の文法もあります。
TRUNCATE TABLE customers;
DELETE文とTRUNCATE文はどちらもテーブルを空にできますが、性質はかなり異なります。
| 比較項目 | DELETE文 | TRUNCATE文 |
|---|---|---|
| WHERE句 | 使える(部分削除が可能) | 使えない(全件削除のみ) |
| 処理速度 | 行単位の削除で比較的遅い | テーブルごと再作成に近く高速 |
| AUTO_INCREMENTの値 | リセットされない | リセットされる |
| ロールバック | トランザクション内で取り消せる | 製品・設定によっては取り消せない場合がある |
条件付きで一部だけ削除したいならDELETE文、テーブルを丸ごと空にしたいだけならTRUNCATE文、という使い分けが基本です。
MySQL(InnoDB)ではTRUNCATE文もトランザクション内でロールバックできますが、製品によって挙動が異なるため、初めて使うDB製品では事前に確認しておくことをおすすめします。
削除ではなく論理削除という選択肢
実務では、DELETE文で物理的にデータを消す物理削除ではなく、status列などのフラグで「削除済み」を表す論理削除を採用するケースも多くあります。
-- 物理削除ではなく、論理削除でフラグを立てる
UPDATE customers SET status = '削除済み' WHERE id = 5;
論理削除にしておけば、誤って削除してしまった場合でもデータ自体は残っているため復旧が容易です。
一方でテーブルにデータが溜まり続けるため、通常のSELECT文には常にWHERE status != '削除済み'のような条件を付ける必要が出てくる、という運用コストもあります。
「本当に物理的に消してよいデータか」を見極めたうえで、DELETE文と論理削除のどちらを使うか選ぶとよいでしょう。
まとめ
この記事のポイント
- DELETE文はテーブルから条件に合致した行を削除するDML文
- WHERE句を忘れると全件削除されてしまうため、DELETE前に同じ条件でSELECTして対象を確認する習慣が重要
- 外部キー制約があると、子テーブルにデータが残ったまま親テーブルの行は削除できない
- 全件削除ならTRUNCATE文、部分削除や取り消しの可能性を残したいならDELETE文、復旧しやすさを重視するなら論理削除という選択肢もある
次に読むべき記事
DELETE文はWHERE句のミスが即座にデータ消失につながる操作です。
次回は、複数のSQL文をひとまとまりの処理として扱い、途中で失敗したら元に戻せるトランザクションの基本:COMMIT・ROLLBACKを解説します。
タグ: SQL, 初心者向け, DML