この記事では、SQLのDELETE文で複数の条件を指定して、安全かつ正確にデータを削除する方法を詳しく解説します。
間違った削除操作を防ぎ、目的のデータのみを確実に削除するテクニックをマスターしましょう。
DELETE文の基本構文

基本的な構文
DELETE FROM テーブル名
WHERE 条件式;
各要素の説明
- DELETE FROM:削除コマンドとテーブル指定
- テーブル名:削除対象のテーブル
- WHERE:削除条件を指定するキーワード
- 条件式:削除対象を絞り込む条件
DELETE文の動作原理
実行プロセス
- WHERE句の条件を評価
- 条件に一致する行を特定
- 該当する行をテーブルから削除
- 削除された行数を返却
重要な注意点
- WHERE句を省略すると全データが削除される
- 削除されたデータは通常復元できない
- トランザクション内でない限り、即座に確定される
サンプルテーブルを使った実例
テーブル設計例
実際の操作を理解するために、以下のサンプルテーブルを使用します:
-- 顧客テーブルの作成
CREATE TABLE customers (
id INT PRIMARY KEY,
name VARCHAR(100),
age INT,
city VARCHAR(50),
membership_status VARCHAR(20),
last_login_date DATE,
account_balance DECIMAL(10,2)
);
-- サンプルデータの挿入
INSERT INTO customers VALUES
(1, '田中太郎', 28, '東京', 'active', '2024-01-15', 15000.00),
(2, '佐藤花子', 35, '大阪', 'inactive', '2023-12-01', 0.00),
(3, '鈴木一郎', 42, '東京', 'active', '2024-01-20', 25000.00),
(4, '高橋恵子', 19, '京都', 'active', '2024-01-18', 5000.00),
(5, '伊藤守', 67, '大阪', 'inactive', '2023-10-15', 100.00),
(6, '渡辺幸子', 25, '京都', 'suspended', '2023-11-20', 0.00),
(7, '山田次郎', 33, '東京', 'active', '2024-01-22', 18000.00),
(8, '中村美穂', 29, '大阪', 'active', '2024-01-19', 12000.00);
テーブル構造の確認
SELECT * FROM customers;
複数条件を指定するDELETE文
AND演算子を使った条件指定
すべての条件を満たす行を削除
-- 東京在住かつ非アクティブな顧客を削除
DELETE FROM customers
WHERE city = '東京' AND membership_status = 'inactive';
年齢と残高の複数条件
-- 30歳以上かつ残高が0円の顧客を削除
DELETE FROM customers
WHERE age >= 30 AND account_balance = 0.00;
3つ以上の条件を組み合わせ
-- 大阪在住、40歳以上、最終ログインが半年以上前の顧客を削除
DELETE FROM customers
WHERE city = '大阪'
AND age >= 40
AND last_login_date < '2023-07-01';
OR演算子を使った条件指定
いずれかの条件を満たす行を削除
-- 残高が0円または停止状態の顧客を削除
DELETE FROM customers
WHERE account_balance = 0.00 OR membership_status = 'suspended';
複数の地域指定
-- 大阪または京都の顧客を削除
DELETE FROM customers
WHERE city = '大阪' OR city = '京都';
年齢範囲の指定
-- 18歳未満または65歳以上の顧客を削除
DELETE FROM customers
WHERE age < 18 OR age >= 65;
括弧を使った複雑な条件
論理演算の優先順位を明確化
-- (大阪または京都在住) かつ (非アクティブまたは停止状態) の顧客を削除
DELETE FROM customers
WHERE (city = '大阪' OR city = '京都')
AND (membership_status = 'inactive' OR membership_status = 'suspended');
年齢と地域の組み合わせ
-- 東京在住の30歳以上、または大阪在住の25歳以下の顧客を削除
DELETE FROM customers
WHERE (city = '東京' AND age >= 30)
OR (city = '大阪' AND age <= 25);
IN演算子を使った条件指定
複数値の指定
複数の値から選択
-- 特定の会員ステータスの顧客を削除
DELETE FROM customers
WHERE membership_status IN ('inactive', 'suspended', 'banned');
複数のIDを指定
-- 特定のIDの顧客を削除
DELETE FROM customers
WHERE id IN (2, 4, 6, 8);
NOT IN演算子
除外条件の指定
-- アクティブではない顧客を削除
DELETE FROM customers
WHERE membership_status NOT IN ('active');
BETWEEN演算子を使った範囲指定

数値範囲での削除
-- 年齢が20歳から30歳の顧客を削除
DELETE FROM customers
WHERE age BETWEEN 20 AND 30;
日付範囲での削除
-- 2023年にログインした顧客を削除
DELETE FROM customers
WHERE last_login_date BETWEEN '2023-01-01' AND '2023-12-31';
金額範囲での削除
-- 残高が1000円から10000円の顧客を削除
DELETE FROM customers
WHERE account_balance BETWEEN 1000.00 AND 10000.00;
サブクエリを使った高度な削除
単一テーブルでのサブクエリ
-- 平均年齢より若い顧客を削除
DELETE FROM customers
WHERE age < (SELECT AVG(age) FROM customers);
注意:同じテーブルを参照するサブクエリは、データベースによって制限がある場合があります。
複数テーブルを使ったサブクエリ
-- 注文テーブルの例
CREATE TABLE orders (
id INT PRIMARY KEY,
customer_id INT,
order_date DATE,
total_amount DECIMAL(10,2)
);
-- 過去1年間注文のない顧客を削除
DELETE FROM customers
WHERE id NOT IN (
SELECT DISTINCT customer_id
FROM orders
WHERE order_date >= '2023-01-01'
AND customer_id IS NOT NULL
);
EXISTS演算子を使った削除
-- 注文履歴がない顧客を削除
DELETE FROM customers
WHERE NOT EXISTS (
SELECT 1
FROM orders
WHERE orders.customer_id = customers.id
);
LIKE演算子を使ったパターンマッチング
文字列パターンでの削除
-- 名前が「田中」で始まる顧客を削除
DELETE FROM customers
WHERE name LIKE '田中%';
ワイルドカードの使用例
-- 名前に「子」が含まれる顧客を削除
DELETE FROM customers
WHERE name LIKE '%子%';
複数のパターン条件
-- 名前が「田中」または「佐藤」で始まる顧客を削除
DELETE FROM customers
WHERE name LIKE '田中%' OR name LIKE '佐藤%';
NULL値の扱い
NULL値を含む条件
-- 最終ログイン日がNULLの顧客を削除
DELETE FROM customers
WHERE last_login_date IS NULL;
NULL値を除外する条件
-- 最終ログイン日がNULLでない古い顧客を削除
DELETE FROM customers
WHERE last_login_date IS NOT NULL
AND last_login_date < '2023-01-01';
安全なDELETE操作のベストプラクティス

事前確認の重要性
STEP 1:SELECTでの事前確認
-- 削除対象を事前に確認
SELECT *
FROM customers
WHERE city = '東京' AND membership_status = 'inactive';
-- 削除される件数を確認
SELECT COUNT(*)
FROM customers
WHERE city = '東京' AND membership_status = 'inactive';
STEP 2:実際の削除実行
DELETE FROM customers
WHERE city = '東京' AND membership_status = 'inactive';
トランザクションの活用
安全な削除の手順
-- トランザクション開始
BEGIN;
-- 削除対象の最終確認
SELECT COUNT(*) FROM customers
WHERE age >= 65 AND last_login_date < '2022-01-01';
-- 削除実行
DELETE FROM customers
WHERE age >= 65 AND last_login_date < '2022-01-01';
-- 削除後の状態確認
SELECT COUNT(*) FROM customers;
-- 問題なければコミット(確定)
COMMIT;
-- 問題があればロールバック(取り消し)
-- ROLLBACK;
データベース別の特徴と注意点

MySQL
MySQL固有の構文
-- LIMIT句を使った件数制限(MySQL)
DELETE FROM customers
WHERE membership_status = 'inactive'
ORDER BY last_login_date ASC
LIMIT 100;
複数テーブルからの削除
-- 結合を使った削除(MySQL)
DELETE c
FROM customers c
JOIN orders o ON c.id = o.customer_id
WHERE o.order_date < '2022-01-01';
PostgreSQL
RETURNING句の活用
-- 削除した行の情報を返す(PostgreSQL)
DELETE FROM customers
WHERE city = '大阪'
RETURNING id, name, city;
SQL Server
OUTPUT句の使用
-- 削除した行の情報を出力(SQL Server)
DELETE FROM customers
OUTPUT DELETED.id, DELETED.name, DELETED.city
WHERE membership_status = 'suspended';
Oracle
ROWNUM を使った件数制限
-- 件数制限付き削除(Oracle)
DELETE FROM customers
WHERE id IN (
SELECT id FROM customers
WHERE membership_status = 'inactive'
AND ROWNUM <= 100
);
パフォーマンス最適化
インデックスの活用
効率的な削除のために
-- WHERE句で使用される列にインデックスを作成
CREATE INDEX idx_customers_city_status
ON customers(city, membership_status);
-- インデックスを活用した削除
DELETE FROM customers
WHERE city = '東京' AND membership_status = 'inactive';
大量データの削除
バッチ削除の実装
-- 段階的な削除(大量データ対応)
DELETE FROM customers
WHERE membership_status = 'inactive'
AND id BETWEEN 1 AND 1000;
DELETE FROM customers
WHERE membership_status = 'inactive'
AND id BETWEEN 1001 AND 2000;
-- 以下繰り返し
エラーハンドリングと復旧

よくあるエラーと対処法
外部キー制約エラー
-- エラー例:外部キー制約があるテーブルからの削除
DELETE FROM customers WHERE id = 1;
-- Error: Cannot delete because of foreign key constraint
-- 対処法:関連データを先に削除
DELETE FROM orders WHERE customer_id = 1;
DELETE FROM customers WHERE id = 1;
構文エラーの回避
-- 間違い:カンマで条件を区切る
-- DELETE FROM customers WHERE city = '東京', age > 30;
-- 正しい:ANDまたはORで条件を結合
DELETE FROM customers WHERE city = '東京' AND age > 30;
データの復旧方法
バックアップからの復旧
- 定期バックアップの確認
- 差分データの復元
- 整合性チェックの実行
レプリケーション環境での復旧
- スレーブサーバーからのデータ復旧
- バイナリログでの復旧
- ポイントインタイム復旧
実用的なDELETE文のパターン
データクリーニング
重複データの削除
-- 重複する顧客データを削除(最新のみ残す)
DELETE c1 FROM customers c1
JOIN customers c2
WHERE c1.id < c2.id
AND c1.name = c2.name
AND c1.city = c2.city;
古いデータの定期削除
-- 6ヶ月以上前の非アクティブ顧客を削除
DELETE FROM customers
WHERE membership_status = 'inactive'
AND last_login_date < DATE_SUB(NOW(), INTERVAL 6 MONTH);
データ移行時の削除
段階的なデータ移行
-- 移行済みデータの削除
DELETE FROM customers
WHERE id IN (
SELECT customer_id
FROM migration_log
WHERE status = 'completed'
);
セキュリティ考慮事項
権限管理
適切な権限設定
- DELETE権限は必要最小限のユーザーにのみ付与
- 本番環境では管理者承認制の導入
- 削除操作のログ記録
監査ログの実装
-- 削除前にログテーブルに記録
INSERT INTO deletion_log (table_name, deleted_data, deleted_by, deleted_at)
SELECT 'customers',
CONCAT('id:', id, ', name:', name),
USER(),
NOW()
FROM customers
WHERE city = '東京' AND membership_status = 'inactive';
よくある質問

DELETE文で複数テーブルから同時に削除できますか?
MySQL では可能です:
DELETE c, o
FROM customers c
JOIN orders o ON c.id = o.customer_id
WHERE c.membership_status = 'inactive';
PostgreSQL や SQL Server では不可ですが、カスケード削除や手動での順次削除で対応できます。
WHERE句なしのDELETE文を実行してしまった場合の対処法は?
即座に行うべきこと:
- トランザクション中なら ROLLBACK
- データベース接続を即座に切断(auto-commitの場合)
- バックアップからの復旧を検討
- レプリケーション環境なら、スレーブサーバーから復旧
削除したデータを復元することはできますか?
復元方法:
- バックアップからの復元(最も確実)
- トランザクションログからの復旧
- レプリケーションサーバーからの復旧
- データ復旧ツールの使用(完全ではない)
大量データを削除する際の注意点は?
推奨アプローチ:
- バッチ処理:小分けして削除
- トランザクション制御:ロールバック可能な範囲で実行
- インデックス最適化:削除対象列にインデックス作成
- リソース監視:CPU・メモリ・ディスクI/O の確認
まとめ
SQLのDELETE文で複数条件を指定することは、正確で安全なデータ削除の基本です。
重要なポイント
- 事前確認:SELECTで削除対象を必ず確認
- 複数条件:AND、OR、括弧を適切に使用
- トランザクション:重要な削除操作では必須
- バックアップ:削除前の確実なバックアップ
条件指定の方法まとめ
演算子 | 用途 | 例 |
---|---|---|
AND | すべての条件を満たす | WHERE age >= 18 AND city = '東京' |
OR | いずれかの条件を満たす | WHERE status = 'inactive' OR status = 'suspended' |
IN | 複数値のいずれかに一致 | WHERE city IN ('東京', '大阪', '京都') |
BETWEEN | 範囲指定 | WHERE age BETWEEN 20 AND 65 |
LIKE | パターンマッチング | WHERE name LIKE '田中%' |
サブクエリ | 他テーブルの条件参照 | WHERE id IN (SELECT customer_id FROM orders) |
コメント