開發環境 (Windows) 不區分表名大小寫,生產環境 (Linux) **區分大小寫** (`lower_case_table_names=0`)。遷移上線前需統一將所有表名轉為大寫,避免代碼中硬編碼表名大小寫不一致導致 `Table 'xxx' doesn't exist` 錯誤。
利用 `information_schema.TABLES` 獲取所有表名,構建 `RENAME TABLE` 動態語句逐一執行。
DELIMITER //
DROP PROCEDURE IF EXISTS uppercase_tables //
CREATE PROCEDURE uppercase_tables(IN dbname VARCHAR(200))
BEGIN
DECLARE done INT DEFAULT 0;
DECLARE oldname VARCHAR(200);
DECLARE newname VARCHAR(200);
DECLARE isNotSame TINYINT DEFAULT 0;
DECLARE sql_stmt TEXT;
-- 游標:查詢指定資料庫所有表名
DECLARE cur CURSOR FOR
SELECT TABLE_NAME
FROM information_schema.TABLES
WHERE TABLE_SCHEMA = dbname;
-- 找不到記錄時結束循環
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
OPEN cur;
REPEAT
FETCH cur INTO oldname;
IF NOT done THEN
-- 轉大寫
SET newname = UPPER(oldname);
-- 二進制比較:區分大小寫判斷是否真正不同
SET isNotSame = (newname <> BINARY oldname);
-- 僅在名稱確實改變時執行 RENAME
IF isNotSame THEN
SET sql_stmt = CONCAT('RENAME TABLE `', dbname, '`.`', oldname, '` TO `', dbname, '`.`', newname, '`');
-- 準備並執行動態 SQL
PREPARE stmt FROM sql_stmt;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
-- 可選:記錄操作日誌
-- INSERT INTO rename_log (old_name, new_name, db_name, exec_time) VALUES (oldname, newname, dbname, NOW());
END IF;
END IF;
UNTIL done END REPEAT;
CLOSE cur;
END //
DELIMITER ;
-- 呼叫預存程序,傳入目標資料庫名稱
CALL uppercase_tables('your_database_name');
| 技術點 | 實作方式 | 作用 |
|---|---|---|
| information_schema.TABLES | SELECT TABLE_NAME WHERE TABLE_SCHEMA=dbname | 獲取指定庫所有表名,跨引擎通用 |
| UPPER() | SET newname = UPPER(oldname) | MySQL 內建大寫轉換函數 |
| BINARY 比較 | newname <> BINARY oldname | 強制區分大小寫比較,避免 'abc' = 'ABC' 判定為相等 |
| 動態 SQL | PREPARE/EXECUTE/DEALLOCATE | 運行時構建並執行 DDL,繞過預存程序不支援直接 DDL 限制 |
| 反引號包裹 | `db`.`table` | 防止保留字、特殊字元導致語法錯誤 |
| 游標循環 | REPEAT ... UNTIL done END REPEAT | 逐行處理結果集,標準預存程序模式 |
DELIMITER //
CREATE PROCEDURE uppercase_all_databases()
BEGIN
DECLARE done INT DEFAULT 0;
DECLARE db_name VARCHAR(64);
DECLARE cur CURSOR FOR
SELECT SCHEMA_NAME
FROM information_schema.SCHEMATA
WHERE SCHEMA_NAME NOT IN ('mysql','information_schema','performance_schema','sys');
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
OPEN cur;
REPEAT
FETCH cur INTO db_name;
IF NOT done THEN
CALL uppercase_tables(db_name);
END IF;
UNTIL done END REPEAT;
CLOSE cur;
END //
DELIMITER ;
-- 一鍵處理所有業務庫
CALL uppercase_all_databases();
| 錯誤 | 原因 | 解決 |
|---|---|---|
| ERROR 1050 (42S01): Table 'DB.TABLE' already exists | 目標大寫表名已存在 (如同時有 user 和 USER) | 先手工處理衝突表,或修改程序加入衝突檢測邏輯 |
| ERROR 1146 (42S02): Table 'db.table' doesn't exist | 表名在 RENAME 過程中被並發操作修改 | 鎖定資料庫 `FLUSH TABLES WITH READ LOCK` 執行 (會阻塞寫入) |
| 外鍵約束失敗 | 引用表未同步重命名 | 先 `SET FOREIGN_KEY_CHECKS=0;` 批次重命名,完成後恢復 |
| 權限不足 | 執行帳號無 ALTER/DROP 權限 | 授予 `GRANT ALTER, DROP, CREATE ON db.* TO user@host;` |
-- 檢查所有表名是否為大寫
SELECT TABLE_NAME FROM information_schema.TABLES
WHERE TABLE_SCHEMA = 'your_db' AND TABLE_NAME <> UPPER(TABLE_NAME) COLLATE utf8mb4_bin;
-- 空結果集 = 全部已轉大寫
此預存程序已在多個 TB 級資料庫遷移專案中驗證可靠,配合完整備份與代碼同步修改,可安全完成 Linux 環境下的表名大小寫統一工作。