ページの作成
親となるページを選択してください。
親ページに紐づくページを子ページといいます。
例: 親=スポーツ, 子1=サッカー, 子2=野球
子ページを親ページとして更に子ページを作成することも可能です。
例: 親=サッカー, 子=サッカーのルール
親ページはいつでも変更することが可能なのでとりあえず作ってみましょう!
| この記事の要点 |
|
DELETE 文とは
DELETE 文は、SQL でテーブルから既存の行を削除するための DML (Data Manipulation Language) ステートメントです。Oracle、MySQL、PostgreSQL、SQL Server など主要な RDBMS で共通して使えます。
誤って実行すると業務データを失うリスクが大きいため、本記事では構文だけでなく安全に運用するための作法もまとめます。
基本構文
DELETE FROM テーブル名
WHERE 削除条件;例として、users テーブルから id = 100 の行を削除する場合は次のように書きます。
DELETE FROM users
WHERE id = 100;
WHERE 句を忘れると全行削除される
DELETE 文で最も危険なのは、WHERE 句を忘れて全行を削除してしまうことです。次の SQL はテーブルのすべての行を消します。
-- 危険: users テーブルの全行が消える
DELETE FROM users;本番環境では、DELETE を実行する前に必ず同じ WHERE 句で SELECT して件数を確認するのが鉄則です。
-- 1) 削除前: 件数確認
SELECT COUNT(*) FROM users WHERE last_login < '2020-01-01';
-- 2) 期待件数なら DELETE 実行
DELETE FROM users WHERE last_login < '2020-01-01';
-- 3) コミット
COMMIT;
トランザクションと ROLLBACK
Oracle や PostgreSQL では暗黙的にトランザクションが始まるため、COMMIT を実行するまで変更は確定しません。誤って削除した場合は ROLLBACK で元に戻せます。
-- Oracle / PostgreSQL のセッション
DELETE FROM orders WHERE order_id = 999;
-- まだコミットしていない
ROLLBACK; -- 削除を取り消すMySQL の InnoDB エンジンも同様にトランザクションをサポートしますが、デフォルト設定では autocommit=1 となっており、各文が即座にコミットされます。明示的にトランザクションを使う場合は START TRANSACTION で開始します。
-- MySQL
START TRANSACTION;
DELETE FROM orders WHERE order_id = 999;
ROLLBACK; -- まだ COMMIT していなければ取り消せる
JOIN を使った削除
関連テーブルを参照しながら削除したい場合は、サブクエリや JOIN を使います。書き方は DBMS によって少し異なります。
Oracle / PostgreSQL (サブクエリ)
-- 退会済みユーザーの注文をすべて削除
DELETE FROM orders
WHERE user_id IN (
SELECT id FROM users WHERE status = 'withdrawn'
);
MySQL (マルチテーブル DELETE)
DELETE o
FROM orders o
JOIN users u ON o.user_id = u.id
WHERE u.status = 'withdrawn';
RETURNING 句で削除内容を取得 (PostgreSQL)
PostgreSQL では、削除と同時に削除した行の内容を返す RETURNING 句が便利です。「念のため履歴を残す」「削除した数を確認する」用途に向きます。
DELETE FROM orders
WHERE order_date < '2020-01-01'
RETURNING id, user_id, total_price;
DELETE と TRUNCATE と DROP の違い
「テーブルを空にする」操作には DELETE 以外の選択肢もあります。用途に応じて選び分けましょう。
| 命令 | 分類 | WHERE | ROLLBACK | 速度 | テーブル定義 |
|---|---|---|---|---|---|
| DELETE | DML | 可 | 可 | 遅い(行単位) | 残る |
| TRUNCATE | DDL | 不可 | 不可 (DBMS 依存) | 速い | 残る |
| DROP TABLE | DDL | 不可 | 不可 (DBMS 依存) | 速い | 消える |
「全行削除して定義は残す」なら TRUNCATE が高速ですが、トリガが発火しない、ROLLBACK できない(DBMS による)、外部キー制約に阻まれる、など独自の制約があります。安全側に倒すなら DELETE + COMMIT が無難です。
外部キー制約と CASCADE
外部キー制約が貼られているテーブルから削除しようとすると、子テーブルに参照されている行は削除できずエラーになります。これを自動で連鎖削除させたい場合は、外部キー定義時に ON DELETE CASCADE を指定します。
CREATE TABLE orders (
id INT PRIMARY KEY,
user_id INT,
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
);
-- users から削除すると orders 側も自動的に削除される
DELETE FROM users WHERE id = 100;CASCADE は便利ですが、意図せず大量の子レコードを巻き込んで削除してしまう事故も起きやすいので、業務テーブルでは慎重に検討してください。
論理削除という選択肢
業務システムでは、物理的に DELETE するのではなく deleted_at や delete_flag といったカラムでマークだけする論理削除が広く採用されています。誤削除からの復旧、監査ログ、関連データの整合性維持などの観点で物理削除より柔軟です。
DELETE 文の内部動作とパフォーマンス
DELETE 文は単に行を消すだけでなく、各種ログ・インデックス・トリガを連動して処理します。InnoDB なら REDO ログと UNDO ログに変更が記録され、各インデックスエントリが論理的に削除済みとマークされます。実際の物理スペースは即座に解放されず、後続のパージ処理や OPTIMIZE TABLE で回収される設計です。そのため、数百万行を一気に削除する DELETE は非常に時間がかかり、ログ領域も圧迫するのが定石です。大量削除では数千〜数万行ずつ分割して COMMIT する、夜間帯に実行する、メンテナンスウィンドウで TRUNCATE を使う、といった工夫が必要になります。
LIMIT 付き DELETE で安全に分割
MySQL では DELETE FROM t WHERE 条件 LIMIT 1000 のように LIMIT を付けて、一度に削除する行数を制限できます。これをスクリプトでループさせれば、長時間ロックを取り続けることなく大量削除を進められます。PostgreSQL や Oracle は DELETE に LIMIT を直接付けられないため、サブクエリで主キーを 1000 件抽出してから WHERE IN で削除するパターンが定番です。本番運用では、削除進捗をログに残し、各バッチの間で短時間 sleep を挟むことで、レプリケーション遅延やバッファプール汚染も抑えられます。
削除時のロックとデッドロック
DELETE は対象行に排他ロック (X ロック) を取得し、コミットされるまで他のトランザクションからの更新を待たせます。複数のセッションが同じ行を異なる順序で削除/更新しようとすると、デッドロックが発生してどちらかがロールバックされます。デッドロックを減らすには、すべてのトランザクションで同じ順序で行をロックすることが基本です。たとえば「常に id の昇順で削除する」というルールを徹底すれば、循環待ちが発生しにくくなります。デッドロック発生時は DBMS が自動的に片方を犠牲にしてエラーにするため、アプリケーション側でリトライ処理を入れておくのが堅実です。
ORM での DELETE
Laravel Eloquent や Django ORM など、現代の Web フレームワークでは ORM 経由で DELETE することが多くなります。User::where('status', 'inactive')->delete() のような呼び出しは、内部で DELETE FROM users WHERE status = 'inactive' を発行します。ORM は論理削除(SoftDeletes)も標準でサポートしており、SoftDeletes trait を使うと deleted_at カラムへの UPDATE に置き換わり、通常クエリでは削除済み行が自動的に除外されます。物理削除したいときは forceDelete() を呼ぶ、削除済み行も含めて検索したいときは withTrashed() を呼ぶ、というインターフェイスが提供されています。
監査とリカバリ
業務システムでは「いつ・誰が・どのデータを削除したか」を残すことが法令や社内ポリシーで求められるケースが多くあります。トリガで監査テーブルに削除内容を記録する、あるいはアプリケーションログに DELETE 文と実行ユーザーを残す、CDC (Change Data Capture) で変更ストリームをイベントとして配信するといった選択肢があります。万一の誤削除に備えて、定期的なバックアップとポイントインタイムリカバリを設定しておくことが、運用上の最後の防波堤になります。
関連記事
ページの作成
親となるページを選択してください。
親ページに紐づくページを子ページといいます。
例: 親=スポーツ, 子1=サッカー, 子2=野球
子ページを親ページとして更に子ページを作成することも可能です。
例: 親=サッカー, 子=サッカーのルール
親ページはいつでも変更することが可能なのでとりあえず作ってみましょう!
子ページはありません
人気ページ
- 1 Eclipseで「サーバーに追加または除去できるリソースがありません。」の原因と対処法
- 2 tomcat の起動 / 停止ログと catalina.log・catalina.out の違い
- 3 JavaScript base URL 取得方法|window.location.origin と SSR/Node.js 対応
- 4 YouTube Data API v3 エラー一覧|403/400/404 の主要原因と切り分け
- 5 Spring Frameworkのアノテーション一覧
- 6 Laravel エラー一覧|500/Blade/DB 接続/ルーティングの代表エラー
- 7 3Dグラフィックスとは|モデリング/レンダリング/主要ソフトウェア (Blender / Maya)
- 8 【Spring】@Valueアノテーションとは
- 9 CATALINA_HOME の確認方法 (Linux / Mac)
- 10 【Spring】@Autowiredアノテーションとは
最近更新/作成されたページ
- IPv6とは|128bitアドレス・コロン16進表記/::省略・リンクローカル・SLAAC・デュアルスタック NEW 2026-06-22 12:34:44
- VPNとは|暗号トンネル・サイト間/リモートアクセス・IPsec/SSL-VPN/WireGuardを解説 NEW 2026-06-22 12:19:10
- MAC アドレスフィルタリングの仕組みと限界 | ネットワーク入門 NEW 2026-06-22 12:19:10
- WebRTC とは ブラウザ間 P2P の音声・映像・データ通信 | ネットワーク入門 NEW 2026-06-22 12:17:25
- gRPC とは HTTP/2 + Protocol Buffers の高速 RPC | ネットワーク入門 NEW 2026-06-22 12:17:25
- HTTP/3 (QUIC) とは UDP ベースの低遅延 Web 通信 | ネットワーク入門 NEW 2026-06-22 12:17:25
- HTTP/2 とは 多重化・HPACK・バイナリフレーム | ネットワーク入門 NEW 2026-06-22 12:17:25
- Web通信プロトコル入門 HTTP/2・HTTP/3・WebSocket・gRPC・WebRTC | ネットワーク入門 NEW 2026-06-22 12:17:25
- WebSocket とは 全二重リアルタイム通信 ws/wss | ネットワーク入門 NEW 2026-06-22 12:17:25
- ファイアウォールとは|パケットフィルタ・ステートフル・DMZ・次世代FW(L4/L7)を解説 NEW 2026-06-22 12:17:24
- iptables/nftablesとは|テーブル・チェーン・ルール例・永続化をLinux視点で解説 NEW 2026-06-22 12:17:24
- HAProxy とは frontend/backend と設定例 | ネットワーク入門 NEW 2026-06-22 12:17:24
- 証明書と認証局(CA)とは|X.509・信頼チェーン・DV/OV/EV・失効(CRL/OCSP)を解説 NEW 2026-06-22 12:17:24
- CDN とは エッジキャッシュ・TTL・Cloudflare/CloudFront | ネットワーク入門 NEW 2026-06-22 12:17:24
- TLS/SSLの仕組み|ハンドシェイク・暗号スイート・前方秘匿性・証明書検証をわかりやすく解説 NEW 2026-06-22 12:17:24
コメントを削除してもよろしいでしょうか?