在資料庫架構演進的過程中,我們經常需要動態調整表結構,例如新增欄位或建立索引。但在執行 ALTER TABLE 之前,若不先檢查物件是否已存在,就會拋出錯誤導致腳本中斷。MySQL 雖無內建 IF NOT EXISTS 擴充語法支援欄位與索引層級的判斷,但我們可以善用 information_schema 系統視圖搭配預存程序,優雅地實現「不存在才建立」的邏輯。
核心思路是查詢 information_schema.columns 視圖,依據資料庫名稱、資料表名稱與欄位名稱三個維度進行精確比對。以下範例示範如何為 rtc_order 表安全新增 IfUpSend 欄位:
DROP PROCEDURE IF EXISTS schema_change;
DELIMITER //
CREATE PROCEDURE schema_change()
BEGIN
DECLARE CurrentDatabase VARCHAR(64);
SELECT DATABASE() INTO CurrentDatabase;
IF NOT EXISTS (
SELECT 1
FROM information_schema.columns
WHERE table_schema = CurrentDatabase
AND table_name = 'rtc_order'
AND column_name = 'IfUpSend'
) THEN
ALTER TABLE rtc_order
ADD COLUMN `IfUpSend` BIT NOT NULL DEFAULT 0 COMMENT '是否上傳';
END IF;
END//
DELIMITER ;
CALL schema_change();
關鍵點解析:
DATABASE() 動態取得當前資料庫名稱,避免硬編碼提升可移植性IF NOT EXISTS 子查詢採用 SELECT 1 而非 SELECT *,減少不必要的資料傳輸同理,索引資訊儲存在 information_schema.statistics 視圖中,透過 index_name 欄位即可精準定位:
DROP PROCEDURE IF EXISTS schema_change;
DELIMITER //
CREATE PROCEDURE schema_change()
BEGIN
DECLARE CurrentDatabase VARCHAR(64);
SELECT DATABASE() INTO CurrentDatabase;
IF NOT EXISTS (
SELECT 1
FROM information_schema.statistics
WHERE table_schema = CurrentDatabase
AND table_name = 'rtc_phototype'
AND index_name = 'idx_imgtype'
) THEN
ALTER TABLE `rtc_phototype`
ADD INDEX idx_imgtype (`imgtype`);
END IF;
END//
DELIMITER ;
CALL schema_change();
idx_ 前綴,欄位採用駝峰或底線風格統一,便於後續維護與搜尋掌握這兩段核心範本,即可在自動化部署、CI/CD 流水線或手動維護中,安全且冪等地管理 MySQL 結構變更,避免重複執行導致的報錯風險。