はじめに
データベース管理において、データの削除は非常に重要な操作の一つです。不要になったレコードを適切に削除することで、データベースのパフォーマンスを維持し、ストレージ容量を効率的に使用できます。
本記事では、PostgreSQL 16におけるDELETE文の基本的な使い方から応用的なテクニックまで、実践的な例を交えながら詳しく解説します。初心者の方でも安心して学べるよう、段階的に説明していきますので、ぜひ最後までお読みください。
この記事で分かること
この記事を読むことで、以下の内容が理解できるようになります。
- DELETE文の基本構文と使い方
- WHERE句を使った条件付き削除の方法
- 複数の条件を組み合わせた削除テクニック
- JOINを使った高度な削除方法
- RETURNING句による削除データの取得
- トランザクションを使った安全な削除操作
- 削除時の注意点とベストプラクティス
これらの知識を身につけることで、PostgreSQLデータベースのデータを安全かつ効率的に管理できるようになります。
稼働環境
本記事の操作は、以下の環境で動作確認を行っています。
- OS: Windows Server 2025(64bit)
- データベース: PostgreSQL 16
- 接続ツール: psql(PostgreSQL標準コマンドラインツール)
※他のOSやPostgreSQLのバージョンでも基本的な操作は同じですが、一部の機能や表示が異なる場合があります。
PostgreSQL DELETE文とは
DELETE文は、データベースのテーブルから既存のレコード(行)を削除するためのSQL文です。SELECT文でデータを取得し、INSERT文でデータを追加し、UPDATE文でデータを更新するのと同様に、DELETE文はデータベース操作の基本となる重要なコマンドです。
削除操作は一度実行すると元に戻すことが難しいため、慎重に行う必要があります。特に本番環境では、必ず事前にバックアップを取得し、WHERE句で削除対象を明確に指定することが重要です。
DELETE文の基本構文
PostgreSQLのDELETE文の基本構文は以下の通りです。
DELETE FROM テーブル名
WHERE 条件;各要素の意味を説明します。
- DELETE FROM: 削除操作を開始するキーワード
- テーブル名: データを削除するテーブルの名前
- WHERE: 削除条件を指定する句(省略すると全レコードが削除されます)
- 条件: どのレコードを削除するかを指定する条件式
WHERE句を省略すると、テーブル内の全てのデータが削除されてしまうため、必ず削除対象を明確に指定することが推奨されます。
実践的なDELETE文の使い方
ここからは、実際の例を使ってDELETE文の使い方を学んでいきましょう。
サンプルテーブルの準備
まず、練習用のテーブルを作成します。従業員情報を管理する「employees」テーブルを例として使用します。
-- テーブルの作成
CREATE TABLE employees (
employee_id SERIAL PRIMARY KEY,
employee_name VARCHAR(100) NOT NULL,
department VARCHAR(50),
salary INTEGER,
hire_date DATE,
is_active BOOLEAN DEFAULT true
);
-- サンプルデータの挿入
INSERT INTO employees (employee_name, department, salary, hire_date, is_active)
VALUES
('山田太郎', '営業部', 350000, '2020-04-01', true),
('佐藤花子', '開発部', 420000, '2019-07-15', true),
('鈴木一郎', '営業部', 380000, '2021-01-10', true),
('田中美咲', '総務部', 320000, '2022-03-20', true),
('高橋健太', '開発部', 450000, '2018-05-01', false),
('伊藤由美', '営業部', 340000, '2023-02-14', true),
('渡辺大輔', '開発部', 410000, '2020-09-30', true);基本的な削除操作##
単一条件での削除
特定の従業員を削除する最もシンプルな例です。従業員IDが5のレコードを削除します。
DELETE FROM employees
WHERE employee_id = 5;この操作により、高橋健太さんのレコードが削除されます。##
複数条件での削除(AND条件)
複数の条件を満たすレコードを削除する場合は、AND演算子を使用します。営業部で給料が350000円未満の従業員を削除する例です。
DELETE FROM employees
WHERE department = '営業部'
AND salary < 350000;この場合、伊藤由美さんのレコードが削除されます。##
複数条件での削除(OR条件)
いずれかの条件を満たすレコードを削除する場合は、OR演算子を使用します。
DELETE FROM employees
WHERE department = '総務部'
OR is_active = false;総務部の従業員、または退職済み(is_active = false)の従業員が削除されます。
IN句を使った削除
複数の値のいずれかに一致するレコードを削除する場合、IN句を使うと便利です。
DELETE FROM employees
WHERE employee_id IN (1, 3, 5);従業員ID 1、3、5のレコードが一度に削除されます。
日付条件での削除
特定の日付範囲のデータを削除することもできます。2022年以降に入社した従業員を削除する例です。
DELETE FROM employees
WHERE hire_date >= '2022-01-01';パターンマッチングでの削除
LIKE演算子を使用して、特定のパターンに一致するデータを削除できます。名前に「田」が含まれる従業員を削除する例です。
DELETE FROM employees
WHERE employee_name LIKE '%田%';この場合、山田太郎さんと田中美咲さんが削除されます。
RETURNING句の活用
PostgreSQLでは、RETURNING句を使うことで、削除したレコードの情報を取得できます。これは削除ログを記録する際などに便利です。
DELETE FROM employees
WHERE department = '営業部'
RETURNING employee_id, employee_name, department;実行結果として、削除された従業員の情報が表示されます。
employee_id | employee_name | department
-------------+---------------+------------
1 | 山田太郎 | 営業部
3 | 鈴木一郎 | 営業部
6 | 伊藤由美 | 営業部
(3 rows)
DELETE 3全ての列を取得したい場合は、アスタリスク(*)を使用できます。
DELETE FROM employees
WHERE salary < 350000
RETURNING *;サブクエリを使った削除
サブクエリを使用することで、より複雑な条件でのデータ削除が可能になります
平均値を使った削除
部署ごとの平均給料より低い給料の従業員を削除する例です。
DELETE FROM employees
WHERE salary < (
SELECT AVG(salary)
FROM employees
WHERE department = employees.department
);EXISTS句を使った削除
別テーブルの情報を参照して削除する場合、EXISTS句が便利です。退職者テーブルに登録されている従業員を削除する例です。
-- 退職者テーブルがあると仮定
DELETE FROM employees e
WHERE EXISTS (
SELECT 1
FROM retired_employees r
WHERE r.employee_id = e.employee_id
);JOINを使った削除
PostgreSQLでは、USING句やJOINを使って他のテーブルと結合しながら削除することもできます。
-- 部署テーブルと結合して、廃止された部署の従業員を削除
DELETE FROM employees e
USING departments d
WHERE e.department = d.department_name
AND d.is_closed = true;トランザクションを使った安全な削除
削除操作は取り消しが難しいため、トランザクションを使用して安全性を高めることが重要です。
基本的なトランザクション
-- トランザクション開始
BEGIN;
-- 削除前のデータ確認
SELECT * FROM employees WHERE department = '営業部';
-- 削除実行
DELETE FROM employees WHERE department = '営業部';
-- 削除後のデータ確認
SELECT * FROM employees;
-- 問題なければコミット、問題があればロールバック
COMMIT;
-- または
-- ROLLBACK;セーブポイントの活用
複数の削除操作を段階的に行う場合、セーブポイントが便利です。
BEGIN;
-- 最初の削除
DELETE FROM employees WHERE salary < 300000;
-- セーブポイントを作成
SAVEPOINT before_second_delete;
-- 2番目の削除
DELETE FROM employees WHERE department = '総務部';
-- 2番目の削除だけを取り消したい場合
ROLLBACK TO SAVEPOINT before_second_delete;
-- 全て確定
COMMIT;削除時の注意点とベストプラクティス
1. WHERE句を必ず確認する
WHERE句を忘れると、テーブルの全データが削除されてしまいます。削除前に必ずSELECT文で確認しましょう。
-- 削除前の確認(推奨)
SELECT * FROM employees WHERE department = '営業部';
-- 確認後に削除
DELETE FROM employees WHERE department = '営業部';2. 外部キー制約に注意
他のテーブルから参照されているレコードは、通常削除できません。
-- エラーが発生する例
DELETE FROM departments WHERE department_id = 1;
-- ERROR: update or delete on table "departments" violates foreign key constraint外部キー制約がある場合は、CASCADE設定を確認するか、参照元のデータを先に削除する必要があります。
3. 大量データの削除
大量のデータを削除する場合は、バッチ処理で分割して実行することを推奨します。
-- 一度に1000件ずつ削除
DELETE FROM employees
WHERE employee_id IN (
SELECT employee_id
FROM employees
WHERE is_active = false
LIMIT 1000
);4. バックアップの取得
重要なデータを削除する前は、必ずバックアップを取得しましょう。
-- 削除前にバックアップテーブルを作成
CREATE TABLE employees_backup AS
SELECT * FROM employees;
-- 削除実行
DELETE FROM employees WHERE department = '営業部';論理削除と物理削除
データベース設計では、実際にレコードを削除する「物理削除」と、削除フラグを立てて見かけ上削除する「論理削除」があります。
物理削除
-- 実際にレコードを削除
DELETE FROM employees WHERE employee_id = 1;メリット:ストレージ容量を節約できる デメリット:データを完全に失う、復元が困難
論理削除
-- 削除フラグを更新するだけ
UPDATE employees
SET is_active = false,
deleted_at = CURRENT_TIMESTAMP
WHERE employee_id = 1;メリット:データの復元が可能、履歴管理ができる デメリット:ストレージ容量を消費し続ける
システムの要件に応じて、適切な削除方法を選択しましょう。
パフォーマンスの考慮事項
インデックスの活用
WHERE句で指定する列にインデックスが設定されていると、削除対象の検索が高速化されます。
-- インデックスの作成
CREATE INDEX idx_employees_department ON employees(department);
-- インデックスを活用した削除
DELETE FROM employees WHERE department = '営業部';VACUUM の実行
PostgreSQLでは、DELETE実行後もディスク領域がすぐには解放されません。定期的にVACUUMを実行しましょう。
-- 手動でVACUUM実行
VACUUM employees;
-- 詳細な統計情報付きで実行
VACUUM VERBOSE employees;
-- 領域を完全に回収(テーブルロックが発生)
VACUUM FULL employees;実行結果のスクリーンショット例
DELETE文を実行すると、以下のような結果が表示されます。
-- 実行例
DELETE FROM employees WHERE department = '営業部';
-- 結果
DELETE 3「DELETE 3」は、3件のレコードが削除されたことを示しています。
RETURNING句を使用した場合:
DELETE FROM employees
WHERE department = '営業部'
RETURNING employee_id, employee_name;
employee_id | employee_name
-------------+---------------
1 | 山田太郎
3 | 鈴木一郎
6 | 伊藤由美
(3 rows)
DELETE 3つまずきポイントと解決策
ポイント1: 全データを削除してしまった
問題: WHERE句を忘れて、テーブルの全データを削除してしまった。
DELETE FROM employees; -- 危険!全データが削除される解決策:
- トランザクション内で作業し、COMMIT前に必ず確認する
- 削除前にバックアップテーブルを作成する
- 本番環境では、DELETE権限を制限する
ポイント2: 外部キー制約エラー
問題: 他のテーブルから参照されているレコードが削除できない。
ERROR: update or delete on table "departments" violates foreign key constraint解決策:
- 参照元のデータを先に削除する
- CASCADE設定を確認する
- 論理削除を検討する
ポイント3: 削除が遅い
問題: 大量のデータ削除に時間がかかる。
解決策:
- WHERE句で使用する列にインデックスを作成する
- バッチ処理で分割して削除する
- TRUNCATEコマンドを検討する(全件削除の場合)
-- 高速な全件削除(ただしトランザクションログに記録されない)
TRUNCATE TABLE employees;ポイント4: ロールバックできない
問題: 削除後にCOMMITしてしまい、データを復元できない。
解決策:
- 必ずBEGINでトランザクションを開始する
- COMMIT前に十分な確認を行う
- 定期的なバックアップを取得する
ポイント5: 条件指定のミス
問題: 意図しないレコードまで削除してしまった。
解決策:
- 削除前に同じ条件でSELECTを実行して確認する
- RETURNING句で削除されたデータを確認する
-- 推奨される手順
-- 1. 削除対象の確認
SELECT * FROM employees WHERE department = '営業部';
-- 2. 確認後に削除
DELETE FROM employees WHERE department = '営業部' RETURNING *;よくある質問(FAQ)
Q1: DELETE文とTRUNCATE文の違いは何ですか?
A: 主な違いは以下の通りです。
- DELETE文: 条件を指定して特定のレコードを削除できます。トランザクションログに記録され、ロールバックが可能です。WHERE句を省略すると全レコードを削除しますが、テーブル構造は残ります。
- TRUNCATE文: テーブルの全レコードを高速に削除します。トランザクションログに最小限しか記録されないため、大量データの削除に適していますが、WHERE句は使用できません。
使い分けの目安として、条件付き削除や少量データの削除にはDELETE、全件削除で高速化が必要な場合はTRUNCATEを使用します。
Q2: 削除したデータを復元することはできますか?
A: 削除方法によって異なります。
- トランザクション内でCOMMIT前: ROLLBACKで復元可能です
- COMMIT後: 基本的に復元不可能です。ただし、以下の方法で復元できる場合があります
- 事前に取得したバックアップから復元
- WAL(Write-Ahead Logging)を使用したポイントインタイムリカバリ
- 論理削除を採用している場合は、フラグを戻すだけで復元可能
重要なデータを扱う場合は、物理削除ではなく論理削除の採用を検討してください。
Q3: 大量のレコードを削除するとパフォーマンスに影響しますか?
A: はい、大量削除は以下の影響があります。
- テーブルロックによる他の操作のブロック
- トランザクションログの肥大化
- ディスクI/Oの増加
対策として、以下の方法を推奨します。
-- バッチ削除の例(1000件ずつ削除)
DO $$
DECLARE
deleted_count INTEGER;
BEGIN
LOOP
DELETE FROM employees
WHERE employee_id IN (
SELECT employee_id
FROM employees
WHERE is_active = false
LIMIT 1000
);
GET DIAGNOSTICS deleted_count = ROW_COUNT;
EXIT WHEN deleted_count = 0;
-- 他の処理への影響を軽減するため、少し待機
PERFORM pg_sleep(0.1);
END LOOP;
END $$;Q4: 削除操作の権限はどのように管理すべきですか?
A: セキュリティとデータ保護の観点から、以下のような権限管理を推奨します。
-- 一般ユーザーにはSELECT権限のみ付与
GRANT SELECT ON employees TO general_user;
-- アプリケーション用ユーザーには必要最小限の権限
GRANT SELECT, INSERT, UPDATE ON employees TO app_user;
-- 削除権限は管理者のみ
GRANT ALL PRIVILEGES ON employees TO admin_user;
本番環境では、削除操作を行う際に承認プロセスを設けることも検討してください。
Q5: DELETEとDROPの違いは何ですか?
A: これらは全く異なる操作です。
- DELETE: テーブル内のレコード(データ)を削除します。テーブル構造は残ります
DELETE FROM employees; -- データのみ削除、テーブルは残る- DROP: テーブル自体を削除します。構造もデータも全て削除されます
DROP TABLE employees; -- テーブルごと完全に削除DROP TABLEは非常に危険な操作なので、実行前に十分な確認が必要です。
まとめ
本記事では、PostgreSQL 16におけるDELETE文の基本から応用まで、幅広く解説しました。重要なポイントを振り返りましょう。
DELETE文の基本:
- DELETE FROM テーブル名 WHERE 条件の構文で、条件に一致するレコードを削除します
- WHERE句を省略すると全レコードが削除されるため、必ず条件を指定しましょう
- RETURNING句を使用すると、削除されたデータの情報を取得できます
安全な削除のためのベストプラクティス:
- 削除前に必ずSELECT文で対象データを確認する
- トランザクションを使用し、COMMIT前に結果を検証する
- 重要なデータは事前にバックアップを取得する
- 本番環境では論理削除の採用を検討する
パフォーマンスの最適化:
- WHERE句で使用する列にインデックスを作成する
- 大量データは分割して削除する
- 定期的にVACUUMを実行してディスク領域を回収する
DELETE文は強力な機能ですが、使い方を誤るとデータを完全に失うリスクがあります。特に本番環境では、削除操作の前に十分な確認と準備を行い、慎重に実行することが重要です。
本記事で学んだ知識を活かして、安全で効率的なデータベース管理を実践してください。