專案遷移、多系統共用資料庫、安全性考量(隱藏表結構),需將所有表前綴從 pre1_ 改為 pre_,或直接加上前綴。
<?php
function renameTablePrefix(PDO $pdo, string $oldPrefix, string $newPrefix, string $database = null): array {
$results = ['success' => [], 'failed' => []];
// 1. 取得所有表名
$sql = $database
? "SELECT TABLE_NAME FROM information_schema.TABLES WHERE TABLE_SCHEMA = ? AND TABLE_NAME LIKE ?"
: "SHOW TABLES";
$stmt = $pdo->prepare($sql);
$database ? $stmt->execute([$database, $oldPrefix . '%']) : $stmt->execute();
$tables = $stmt->fetchAll(PDO::FETCH_COLUMN);
// 2. 逐一重命名
foreach ($tables as $oldName) {
$newName = $newPrefix . substr($oldName, strlen($oldPrefix));
if ($oldName === $newName) continue; // 無變化略過
try {
// RENAME TABLE 不需權限 ALTER,只需 ALTER/DROP/CREATE 權限
$pdo->exec("RENAME TABLE `{$oldName}` TO `{$newName}`");
$results['success'][] = "{$oldName} → {$newName}";
} catch (PDOException $e) {
$results['failed'][] = "{$oldName}: " . $e->getMessage();
}
}
return $results;
}
// 使用範例
$pdo = new PDO('mysql:host=localhost;dbname=myapp', 'root', 'pwd', [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
]);
$res = renameTablePrefix($pdo, 'pre1_', 'pre_');
echo "成功: " . count($res['success']) . ", 失敗: " . count($res['failed']) . "\n";
print_r($res);
function addTablePrefix(PDO $pdo, string $prefix, string $database = null): array {
$sql = $database
? "SELECT TABLE_NAME FROM information_schema.TABLES WHERE TABLE_SCHEMA = ? AND TABLE_NAME NOT LIKE ?"
: "SHOW TABLES";
$stmt = $pdo->prepare($sql);
$database ? $stmt->execute([$database, $prefix . '%']) : $stmt->execute();
$tables = $stmt->fetchAll(PDO::FETCH_COLUMN);
$results = ['success' => [], 'failed' => []];
foreach ($tables as $name) {
$newName = $prefix . $name;
try {
$pdo->exec("RENAME TABLE `{$name}` TO `{$newName}`");
$results['success'][] = "{$name} → {$newName}";
} catch (PDOException $e) {
$results['failed'][] = "{$name}: " . $e->getMessage();
}
}
return $results;
}
| 風險 | 說明 | 對策 |
|---|---|---|
| 外鍵約束 | InnoDB 外鍵引用的表重命名會失敗 | 先 SET FOREIGN_KEY_CHECKS=0,完畢後恢復 1 |
| 視圖/觸發器/存儲過程 | 內部硬編碼表名,重命名後失效 | 先匯出定義、重命名後重新建立,或用工具自動重寫 |
| 程式碼硬編碼表名 | PHP/SQL 腳本中寫死表名 | 全專案搜尋替換、或用常數/配置檔管理表名 |
| 權限不足 | 執行帳號無 ALTER/DROP 權限 | 授予 GRANT ALTER, DROP, CREATE ON db.* TO user |
| 大表鎖定時間長 | RENAME TABLE 會獲取元資料鎖,阻塞讀寫 | 低峰期執行、或用 pt-online-schema-change 類工具 |
| 備份缺失 | 操作失敗無法回滾 | 操作前必備完整備份(mysqldump / 快照) |
<?php
function safeRenamePrefix(PDO $pdo, string $oldPrefix, string $newPrefix): array {
$pdo->exec('SET FOREIGN_KEY_CHECKS = 0');
try {
$res = renameTablePrefix($pdo, $oldPrefix, $newPrefix);
} finally {
$pdo->exec('SET FOREIGN_KEY_CHECKS = 1');
}
return $res;
}
-- 1. 建立新表結構
CREATE TABLE `pre_new_table` LIKE `pre1_old_table`;
-- 2. 複製資料(可分批、可加 WHERE)
INSERT INTO `pre_new_table` SELECT * FROM `pre1_old_table`;
-- 3. 切換(需短暫鎖定)
RENAME TABLE `pre1_old_table` TO `pre1_old_table_bak`, `pre_new_table` TO `pre_new_table`;
-- 4. 驗證無誤後刪除備份
DROP TABLE `pre1_old_table_bak`;
此法不鎖定原表寫入,適合 TB 級大表、7x24 系統。
RENAME TABLE + 關閉外鍵檢查