需對狀態變更表建立歷史記錄:當 triggletest_triggle 表更新時,自動將變更後的數據寫入 triggletest 歷史表。
CREATE TABLE `triggletest_triggle` ( `id` INT(11) NOT NULL, `name` VARCHAR(5) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB; CREATE TABLE `triggletest` ( `seq` INT(11) NOT NULL AUTO_INCREMENT, `id` INT(11) NOT NULL, `name` VARCHAR(5) DEFAULT NULL, PRIMARY KEY (`seq`), KEY `idx_id` (`id`) ) ENGINE=InnoDB;
-- 初始嘗試(在 HeidiSQL 中執行報錯) DROP TRIGGER IF EXISTS test1; CREATE TRIGGER test1 AFTER UPDATE ON triggletest_triggle FOR EACH ROW BEGIN INSERT INTO triggletest(id) VALUES (NEW.id); END;
報錯信息:
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'CREATE TRIGGER test1 AFTER UPDATE ON triggletest_triggle FOR EACH ROW BEGIN ' at line 2
;,觸發器體內含多條語句需臨時修改分隔符。DELIMITER 命令**,直接粘貼含 BEGIN ... END 的觸發器會因內部 ; 被誤判為語句結束而語法錯誤。DELIMITER // ... // DELIMITER ; 模式,可直接執行。在工具中**逐條執行**以下語句,不要一次性批量執行:
DROP TRIGGER IF EXISTS test1; CREATE TRIGGER test1 AFTER UPDATE ON test.triggletest_triggle FOR EACH ROW BEGIN INSERT INTO triggletest(id, name) VALUES (NEW.id, NEW.name); END;
大多數現代 GUI(Navicat 15+、Workbench 8+、DBeaver)已自動識別 BEGIN ... END 塊,單條提交即可成功。
DELIMITER // DROP TRIGGER IF EXISTS test1// CREATE TRIGGER test1 AFTER UPDATE ON test.triggletest_triggle FOR EACH ROW BEGIN INSERT INTO triggletest(id, name) VALUES (NEW.id, NEW.name); END// DELIMITER ;
若觸發器體僅一條語句,可省略 BEGIN ... END,完美兼容所有客戶端:
DROP TRIGGER IF EXISTS test1; CREATE TRIGGER test1 AFTER UPDATE ON test.triggletest_triggle FOR EACH ROW INSERT INTO triggletest(id, name) VALUES (NEW.id, NEW.name);
-- 插入測試數據 INSERT INTO triggletest_triggle VALUES (1, 'A'); -- 觸發更新 UPDATE triggletest_triggle SET name = 'B' WHERE id = 1; -- 查詢歷史表 SELECT * FROM triggletest; -- 預期輸出:seq=1, id=1, name='B'
BEGIN/END、無分隔符煩惱、兼容性最強。CALL sp_log_change(NEW.id, NEW.name),保持觸發器輕量、可測試。SHOW TRIGGERS、INFORMATION_SCHEMA.TRIGGERS 定期審計,防止業務邏輯隱性蔓延到 DB 層。