Skip to content

Instantly share code, notes, and snippets.

@kobitoDevelopment
Created December 21, 2025 04:05
Show Gist options
  • Select an option

  • Save kobitoDevelopment/e22b580322bff1443a6cfa0f48088354 to your computer and use it in GitHub Desktop.

Select an option

Save kobitoDevelopment/e22b580322bff1443a6cfa0f48088354 to your computer and use it in GitHub Desktop.
<?php
/**
* データベース削除の4つのアプローチ
* MySQL + PHP サンプルコード
*/
// ========================================
// 各アプローチの比較と使い分け
// ========================================
/**
* 1. 論理削除(deleted_at)
* メリット: 復元が容易、削除履歴が残る、誤削除に強い、削除日時が分かる
* デメリット: データ量が増える、クエリが複雑になる
* 用途: ユーザーアカウント、重要なマスターデータ、監査証跡が必要な場合
*
* 2. 物理削除
* メリット: データベースがシンプル、ストレージ節約、完全にデータを消去できる
* デメリット: 復元不可、履歴が残らない
* 用途: 一時データ、セッション情報、キャッシュ、個人情報の完全削除
*
* 3. 削除フラグ(is_deleted)
* メリット: シンプル、高速、復元が容易、インデックスが効きやすい
* デメリット: deleted_atより情報が少ない(削除日時が分からない)
* 用途: コンテンツ管理、注文管理、シンプルな論理削除が必要な場合
*
* 4. 削除テーブルへの移動
* メリット: 本テーブルのパフォーマンス維持、監査証跡の保持、削除者の記録も可能
* デメリット: 実装が複雑、トランザクション管理が必要
* 用途: 大量データの削除、データを完全に削除できず保持しておかなければならない
* 責務が要件に含まれる場合、コンプライアンス要件がある場合
*/
// データベース接続設定
$host = 'localhost';
$dbname = 'my_dbname';
$username = 'your_username';
$password = 'your_password';
try {
$pdo = new PDO("mysql:host=$host;dbname=$dbname;charset=utf8mb4", $username, $password);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
die("接続エラー: " . $e->getMessage());
}
// ========================================
// 1. 論理削除(deleted_atカラムを使用)
// ========================================
/**
* テーブル作成例(論理削除用)
* CREATE TABLE users (
* id INT PRIMARY KEY AUTO_INCREMENT,
* name VARCHAR(100),
* email VARCHAR(100),
* created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
* deleted_at TIMESTAMP NULL DEFAULT NULL
* );
*/
function logicalDelete($pdo, $userId) {
$sql = "UPDATE users SET deleted_at = NOW() WHERE id = :id AND deleted_at IS NULL";
$stmt = $pdo->prepare($sql);
$stmt->execute(['id' => $userId]);
return $stmt->rowCount() > 0;
}
function getActiveUsers($pdo) {
$sql = "SELECT * FROM users WHERE deleted_at IS NULL";
$stmt = $pdo->query($sql);
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
function restoreUser($pdo, $userId) {
$sql = "UPDATE users SET deleted_at = NULL WHERE id = :id";
$stmt = $pdo->prepare($sql);
$stmt->execute(['id' => $userId]);
return $stmt->rowCount() > 0;
}
// 使用例
// logicalDelete($pdo, 1);
// $activeUsers = getActiveUsers($pdo);
// ========================================
// 2. 物理削除(完全にデータを削除)
// ========================================
/**
* テーブル作成例(物理削除用)
* CREATE TABLE products (
* id INT PRIMARY KEY AUTO_INCREMENT,
* name VARCHAR(100),
* price DECIMAL(10, 2),
* created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
* );
*/
function physicalDelete($pdo, $productId) {
$sql = "DELETE FROM products WHERE id = :id";
$stmt = $pdo->prepare($sql);
$stmt->execute(['id' => $productId]);
return $stmt->rowCount() > 0;
}
function physicalDeleteWithCondition($pdo, $condition) {
// 例: 1年以上前のデータを削除
$sql = "DELETE FROM products WHERE created_at < DATE_SUB(NOW(), INTERVAL 1 YEAR)";
$stmt = $pdo->query($sql);
return $stmt->rowCount();
}
// 使用例
// physicalDelete($pdo, 5);
// ========================================
// 3. 削除フラグ(is_deletedカラムを使用)
// ========================================
/**
* テーブル作成例(削除フラグ用)
* CREATE TABLE orders (
* id INT PRIMARY KEY AUTO_INCREMENT,
* customer_name VARCHAR(100),
* total_amount DECIMAL(10, 2),
* is_deleted TINYINT(1) DEFAULT 0,
* created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
* updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
* );
*/
function deleteFlagDelete($pdo, $orderId) {
$sql = "UPDATE orders SET is_deleted = 1 WHERE id = :id AND is_deleted = 0";
$stmt = $pdo->prepare($sql);
$stmt->execute(['id' => $orderId]);
return $stmt->rowCount() > 0;
}
function getActiveOrders($pdo) {
$sql = "SELECT * FROM orders WHERE is_deleted = 0";
$stmt = $pdo->query($sql);
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
function undeleteOrder($pdo, $orderId) {
$sql = "UPDATE orders SET is_deleted = 0 WHERE id = :id";
$stmt = $pdo->prepare($sql);
$stmt->execute(['id' => $orderId]);
return $stmt->rowCount() > 0;
}
// 使用例
// deleteFlagDelete($pdo, 10);
// $orders = getActiveOrders($pdo);
// ========================================
// 4. 削除テーブルへの移動
// ========================================
/**
* テーブル作成例(削除テーブルへの移動用)
* CREATE TABLE posts (
* id INT PRIMARY KEY AUTO_INCREMENT,
* title VARCHAR(200),
* content TEXT,
* author_id INT,
* created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
* );
*
* CREATE TABLE deleted_posts (
* id INT PRIMARY KEY,
* title VARCHAR(200),
* content TEXT,
* author_id INT,
* created_at TIMESTAMP,
* deleted_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
* deleted_by INT
* );
*/
function moveToDeletedTable($pdo, $postId, $deletedBy) {
try {
$pdo->beginTransaction();
// 元のデータを取得
$sql = "SELECT * FROM posts WHERE id = :id";
$stmt = $pdo->prepare($sql);
$stmt->execute(['id' => $postId]);
$post = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$post) {
throw new Exception("投稿が見つかりません");
}
// 削除テーブルに挿入
$sql = "INSERT INTO deleted_posts (id, title, content, author_id, created_at, deleted_by)
VALUES (:id, :title, :content, :author_id, :created_at, :deleted_by)";
$stmt = $pdo->prepare($sql);
$stmt->execute([
'id' => $post['id'],
'title' => $post['title'],
'content' => $post['content'],
'author_id' => $post['author_id'],
'created_at' => $post['created_at'],
'deleted_by' => $deletedBy
]);
// 元のテーブルから削除
$sql = "DELETE FROM posts WHERE id = :id";
$stmt = $pdo->prepare($sql);
$stmt->execute(['id' => $postId]);
$pdo->commit();
return true;
} catch (Exception $e) {
$pdo->rollBack();
error_log("削除エラー: " . $e->getMessage());
return false;
}
}
function restoreFromDeletedTable($pdo, $postId) {
try {
$pdo->beginTransaction();
// 削除テーブルからデータを取得
$sql = "SELECT id, title, content, author_id, created_at FROM deleted_posts WHERE id = :id";
$stmt = $pdo->prepare($sql);
$stmt->execute(['id' => $postId]);
$post = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$post) {
throw new Exception("削除された投稿が見つかりません");
}
// 元のテーブルに復元
$sql = "INSERT INTO posts (id, title, content, author_id, created_at)
VALUES (:id, :title, :content, :author_id, :created_at)";
$stmt = $pdo->prepare($sql);
$stmt->execute($post);
// 削除テーブルから削除
$sql = "DELETE FROM deleted_posts WHERE id = :id";
$stmt = $pdo->prepare($sql);
$stmt->execute(['id' => $postId]);
$pdo->commit();
return true;
} catch (Exception $e) {
$pdo->rollBack();
error_log("復元エラー: " . $e->getMessage());
return false;
}
}
// 使用例
// moveToDeletedTable($pdo, 15, 100); // 投稿ID 15を削除(削除者ID 100)
// restoreFromDeletedTable($pdo, 15); // 投稿ID 15を復元
?>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment