MYSQL_ 语法 13 -----CREATE TRIGGER (15)

本文深入解析MySQL触发器的原理及应用,包括INSERT、UPDATE、DELETE触发器的特性,以及BEFORE与AFTER触发时机的区别。阐述了触发器如何在数据操作前后自动执行,确保数据一致性和复杂业务逻辑的实现。

触发器

MySQL 数据库中触发器是一个特殊的存储过程,不同的是执行存储过程要使用 CALL 语句来调用,而触发器的执行不需要使用 CALL 语句来调用,也不需要手工启动,只要一个预定义的事件发生就会被 MySQL自动调用。

引发触发器执行的事件一般如下:

  • 增加一条学生记录时,会自动检查年龄是否符合范围要求。
  • 每当删除一条学生信息时,自动删除其成绩表上的对应记录。
  • 每当删除一条数据时,在数据库存档表中保留一个备份副本。

触发程序的优点如下:

  • 触发程序的执行是自动的,当对触发程序相关表的数据做出相应的修改后立即执行。
  • 触发程序可以通过数据库中相关的表层叠修改另外的表。
  • 触发程序可以实施比 FOREIGN KEY 约束、CHECK 约束更为复杂的检查和操作。

触发器与表关系密切,主要用于保护表中的数据。特别是当有多个表具有一定的相互联系的时候,触发器能够让不同的表保持数据的一致性。

在 MySQL 中,只有执行 INSERT、UPDATE 和 DELETE 操作时才能激活触发器。

在实际使用中,MySQL 所支持的触发器有三种:INSERT 触发器、UPDATE 触发器和 DELETE 触发器。

  1. INSERT 触发器

在 INSERT 语句执行之前或之后响应的触发器。

使用 INSERT 触发器需要注意以下几点:

  • 在 INSERT 触发器代码内,可引用一个名为 NEW(不区分大小写)的虚拟表来访问被插入的行。

  • 在 BEFORE INSERT 触发器中,NEW 中的值也可以被更新,即允许更改被插入的值(只要具有对应的操作权限)。

  • 对于 AUTO_INCREMENT 列,NEW 在 INSERT 执行之前包含的值是 0,在 INSERT 执行之后将包含新的自动生成值。

  • UPDATE 触发器
    在 UPDATE 语句执行之前或之后响应的触发器。

使用 UPDATE 触发器需要注意以下几点:

  • 在 UPDATE 触发器代码内,可引用一个名为 NEW(不区分大小写)的虚拟表来访问更新的值。

  • 在 UPDATE 触发器代码内,可引用一个名为 OLD(不区分大小写)的虚拟表来访问 UPDATE 语句执行前的值。

  • 在 BEFORE UPDATE 触发器中,NEW 中的值可能也被更新,即允许更改将要用于 UPDATE
    语句中的值(只要具有对应的操作权限)。

  • OLD 中的值全部是只读的,不能被更新。 注意:当触发器设计对触发表自身的更新操作时,只能使用 BEFORE 类型的触发器,AFTER
    类型的触发器将不被允许。

  • DELETE 触发器
    在 DELETE 语句执行之前或之后响应的触发器。

使用 DELETE 触发器需要注意以下几点:

  • 在 DELETE 触发器代码内,可以引用一个名为 OLD(不区分大小写)的虚拟表来访问被删除的行。

  • OLD 中的值全部是只读的,不能被更新

  • 总体来说,触发器使用的过程中,MySQL 会按照以下方式来处理错误。

若对于事务性表,如果触发程序失败,以及由此导致的整个语句失败,那么该语句所执行的所有更改将回滚;对于非事务性表,则不能执行此类回滚,即使语句失败,失败之前所做的任何更改依然有效。

若 BEFORE 触发程序失败,则 MySQL 将不执行相应行上的操作。

若在 BEFORE 或 AFTER 触发程序的执行过程中出现错误,则将导致调用触发程序的整个语句失败。

仅当 BEFORE 触发程序和行操作均已被成功执行,MySQL 才会执行AFTER触发程序。

创建触发器(CREATE TRIGGER)

CREATE <触发器名> < BEFORE | AFTER >
<INSERT | UPDATE | DELETE >
ON <表名> FOR EACH Row<触发器主体>
  1. 触发器名
    触发器的名称,触发器在当前数据库中必须具有唯一的名称。如果要在某个特定数据库中创建,名称前面应该加上数据库的名称。
  2. INSERT | UPDATE | DELETE
    触发事件,用于指定激活触发器的语句的种类。
    注意:三种触发器的执行时间如下。
  • INSERT:将新行插入表时激活触发器。例如,INSERT 的 BEFORE 触发器不仅能被 MySQL 的 INSERT
    语句激活,也能被 LOAD DATA 语句激活。
  • DELETE: 从表中删除某一行数据时激活触发器,例如 DELETE 和 REPLACE 语句。
  • UPDATE:更改表中某一行数据时激活触发器,例如 UPDATE 语句。
  1. BEFORE | AFTER
    BEFORE 和 AFTER,触发器被触发的时刻,表示触发器是在激活它的语句之前或之后触发。若希望验证新数据是否满足条件,则使用 BEFORE 选项;若希望在激活触发器的语句执行之后完成几个或更多的改变,则通常使用 AFTER 选项。
  2. 表名
    与触发器相关联的表名,此表必须是永久性表,不能将触发器与临时表或视图关联起来。在该表上触发事件发生时才会激活触发器。同一个表不能拥有两个具有相同触发时刻和事件的触发器。例如,对于一张数据表,不能同时有两个 BEFORE UPDATE 触发器,但可以有一个 BEFORE UPDATE 触发器和一个 BEFORE INSERT 触发器,或一个 BEFORE UPDATE 触发器和一个 AFTER UPDATE 触发器。
  3. 触发器主体
    触发器动作主体,包含触发器激活时将要执行的 MySQL 语句。如果要执行多个语句,可使用 BEGIN…END 复合语句结构
  4. FOR EACH ROW
    一般是指行级触发,对于受触发事件影响的每一行都要激活触发器的动作。例如,使用 INSERT 语句向某个表中插入多行数据时,触发器会对每一行数据的插入都执行相应的触发器动作。

每个表都支持 INSERT、UPDATE 和 DELETE 的 BEFORE 与 AFTER,因此每个表最多支持 6 个触发器。每个表的每个事件每次只允许有一个触发器。单一触发器不能与多个事件或多个表关联。

另外,在 MySQL 中,若需要查看数据库中已有的触发器,则可以使用 SHOW TRIGGERS 语句。
创建 BEFORE 类型触发器

创建 BEFORE 类型触发器

mysql> mysql> DELIMITER $$ mysql> mysql> CREATE TRIGGER tr_ai_check_under_400 -> AFTER UPDATE ON ai_appsortingtaskskus -> FOR EACH ROW -> BEGIN -> DECLARE v_line_number INT; -> DECLARE v_waybill_id VARCHAR(50); -> DECLARE v_qty_sum INT DEFAULT 0; -> DECLARE v_cttime DATETIME; -> DECLARE v_max_id INT DEFAULT 1; -> -> -- 仅当 LastModificationTime 从 NULL 变为非 NULL(即开始分播)时处理 -> IF OLD.LastModificationTime IS NULL AND NEW.LastModificationTime IS NOT NULL THEN -> -> -- 获取对应的 LineNumber 和 WaybillId -> SELECT -> a.LineNumber, -> c.WaybillId -> INTO -> v_line_number, -> v_waybill_id -> FROM ai_appsortingtaskskus a -> INNER JOIN ai_appsortingtaskitems b ON a.ItemId = b.Id -> INNER JOIN ai_appsortingtasks c ON b.TaskId = c.Id -> WHERE a.ItemId = NEW.ItemId -> AND c.IsDeleted = 0 -> AND c.Status = 2 -> LIMIT 1; -> -> -- 如果未查到有效信息,则退出 -> IF v_line_number IS NULL OR v_waybill_id IS NULL THEN -> LEAVE; -- 实际语法错误,此处应改为 BEGIN ... END 控制结构 -> END IF; -> -> -- 开启事务进行加锁检查 -> START TRANSACTION; -> -> -- 🔒 对 ai_devicestatus 中该 LineNumber 的记录加排他锁(即使 CtTime 为空也要锁住) -> -- 注意:主键是 LineNumber,所以可以用主键锁定整行 -> SELECT CtTime INTO v_cttime -> FROM ai_devicestatus -> WHERE LineNumber = v_line_number -> FOR UPDATE; -> -> -- 再次确认是否已记录 CtTime(防幻读) -> IF v_cttime IS NULL THEN -> -> -- 重新计算该 LineNumber + WaybillId 下的待分播总量 -> SELECT COALESCE(SUM(a.Qty), 0) -> INTO v_qty_sum -> FROM ai_appsortingtaskskus a -> INNER JOIN ai_appsortingtaskitems b ON a.ItemId = b.Id -> INNER JOIN ai_appsortingtasks c ON b.TaskId = c.Id -> WHERE -> c.IsDeleted = 0 -> AND c.Status = 2 -> AND a.LastModificationTime IS NULL -> AND a.LineNumber = v_line_number -> AND c.WaybillId = v_waybill_id; -> -> -- 若小于 400,则记录 CtTime 并分配 Id -> IF v_qty_sum < 400 THEN -> -> -- 获取最大 Id + 1,若无则从 1 开始 -> SELECT COALESCE(MAX(Id), 0) + 1 INTO v_max_id FROM ai_devicestatus; -> -> -- 更新 ai_devicestatus 表中的 CtTime 和 Id 字段 -> UPDATE ai_devicestatus -> SET -> CtTime = NOW(), -> Id = v_max_id -> WHERE LineNumber = v_line_number; -> -> END IF; -> -> END IF; -> -> COMMIT; -> -> END IF; -> -> 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 '; END IF; START TRANSACTION; ' at line 31 mysql> mysql> DELIMITER ; mysql>
10-12
[root@yfw ~]# cd /www/wwwroot/szrengjing.com [root@yfw szrengjing.com]# mysql -u szrengjing_com -p Enter password: Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 93707 Server version: 5.7.42-log Source distribution Copyright (c) 2000, 2023, Oracle and/or its affiliates. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql> USE szrengjing_com; Database changed mysql> CREATE TABLE IF NOT EXISTS ecs_user_credit ( -> id INT AUTO_INCREMENT PRIMARY KEY, -> user_id INT NOT NULL UNIQUE, -> score INT DEFAULT 80, -> level VARCHAR(20) AS ( -> CASE -> WHEN score >= 95 THEN '★★★★★' -> WHEN score >= 85 THEN '★★★★☆' -> WHEN score >= 75 THEN '★★★☆☆' -> WHEN score >= 60 THEN '★★☆☆☆' -> ELSE '★☆☆☆☆' -> END -> ) STORED, -> updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP -> ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; Query OK, 0 rows affected, 1 warning (0.00 sec) mysql> CREATE TABLE IF NOT EXISTS ecs_user_credit_log ( -> id BIGINT AUTO_INCREMENT PRIMARY KEY, -> user_id INT NOT NULL, -> old_score INT, -> new_score INT, -> change_value INT, -> reason VARCHAR(100), -> created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP -> ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; Query OK, 0 rows affected, 1 warning (0.00 sec) mysql> DROP TRIGGER IF EXISTS tr_after_update_credit; Query OK, 0 rows affected, 1 warning (0.01 sec) mysql> DROP PROCEDURE IF EXISTS sp_add_credit; Query OK, 0 rows affected, 1 warning (0.00 sec) mysql> DELIMITER ;; mysql> CREATE TRIGGER tr_after_update_credit -> AFTER UPDATE ON ecs_user_credit -> FOR EACH ROW -> BEGIN -> INSERT INTO ecs_user_credit_log (user_id, old_score, new_score, change_value, reason) -> VALUES (NEW.user_id, OLD.score, NEW.score, NEW.score - OLD.score, '系统调整'); -> END;; Query OK, 0 rows affected (0.01 sec) mysql> CREATE PROCEDURE sp_add_credit( -> IN p_user_id INT, -> IN p_change INT, -> IN p_reason VARCHAR(100) -> ) -> BEGIN -> DECLARE current_score INT DEFAULT 80; -> -- 查询当前分数并加锁防止并发 -> SELECT score INTO current_score FROM ecs_user_credit WHERE user_id = p_user_id FOR UPDATE; -> -> -- 插入或更新分数 -> INSERT INTO ecs_user_credit (user_id, score) -> VALUES (p_user_id, current_score + p_change) -> ON DUPLICATE KEY UPDATE score = score + p_change; -> END;; Query OK, 0 rows affected (0.00 sec) mysql> DELIMITER ; mysql> SHOW TABLES LIKE 'ecs_user_credit%'; +---------------------------------------------+ | Tables_in_szrengjing_com (ecs_user_credit%) | +---------------------------------------------+ | ecs_user_credit | | ecs_user_credit_log | +---------------------------------------------+ 2 rows in set (0.00 sec) mysql> SHOW TRIGGERS LIKE 'ecs_user_credit'\G *************************** 1. row *************************** Trigger: tr_update_credit_level Event: UPDATE Table: ecs_user_credit Statement: BEGIN IF NEW.score >= 95 THEN SET NEW.level = '★★★★★'; ELSEIF NEW.score >= 85 THEN SET NEW.level = '★★★★☆'; ELSEIF NEW.score >= 75 THEN SET NEW.level = '★★★☆☆'; ELSEIF NEW.score >= 60 THEN SET NEW.level = '★★☆☆☆'; ELSE SET NEW.level = '★☆☆☆☆'; END IF; END Timing: BEFORE Created: 2025-11-09 05:25:20.26 sql_mode: NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION Definer: szrengjing_com@localhost character_set_client: utf8 collation_connection: utf8_general_ci Database Collation: utf8mb4_general_ci *************************** 2. row *************************** Trigger: tr_after_update_credit Event: UPDATE Table: ecs_user_credit Statement: BEGIN INSERT INTO ecs_user_credit_log (user_id, old_score, new_score, change_value, reason) VALUES (NEW.user_id, OLD.score, NEW.score, NEW.score - OLD.score, '系统调整'); END Timing: AFTER Created: 2025-11-09 06:19:33.39 sql_mode: NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION Definer: szrengjing_com@localhost character_set_client: utf8 collation_connection: utf8_general_ci Database Collation: utf8mb4_general_ci 2 rows in set (0.00 sec) mysql> SHOW PROCEDURE STATUS WHERE Name = 'sp_add_credit'\G *************************** 1. row *************************** Db: szrengjing_com Name: sp_add_credit Type: PROCEDURE Definer: szrengjing_com@localhost Modified: 2025-11-09 06:19:48 Created: 2025-11-09 06:19:48 Security_type: DEFINER Comment: character_set_client: utf8 collation_connection: utf8_general_ci Database Collation: utf8mb4_general_ci 1 row in set (0.00 sec) mysql> CALL sp_add_credit(1, 5, '手动测试加分'); Query OK, 2 rows affected (0.01 sec) mysql> SELECT * FROM ecs_user_credit_log ORDER BY id DESC LIMIT 1\G *************************** 1. row *************************** id: 4 user_id: 1 old_score: 90 new_score: 95 change_value: 5 reason: 系统调整 created_at: 2025-11-09 06:21:06 1 row in set (0.00 sec) mysql> DROP TRIGGER IF EXISTS tr_update_credit_level; Query OK, 0 rows affected (0.01 sec) mysql> CALL sp_add_credit(2, 10, '新用户注册奖励'); Query OK, 1 row affected (0.00 sec) mysql> CALL sp_add_credit(1, -5, '违规扣分测试'); Query OK, 2 rows affected (0.01 sec) mysql> SELECT * FROM ecs_user_credit_log ORDER BY id DESC LIMIT 5\G *************************** 1. row *************************** id: 5 user_id: 1 old_score: 95 new_score: 90 change_value: -5 reason: 系统调整 created_at: 2025-11-09 06:22:39 *************************** 2. row *************************** id: 4 user_id: 1 old_score: 90 new_score: 95 change_value: 5 reason: 系统调整 created_at: 2025-11-09 06:21:06 *************************** 3. row *************************** id: 3 user_id: 1 old_score: 85 new_score: 90 change_value: 5 reason: 测试加分 created_at: 2025-11-09 05:55:47 *************************** 4. row *************************** id: 2 user_id: 1 old_score: 95 new_score: 85 change_value: -10 reason: 评论被举报 created_at: 2025-11-09 05:38:14 *************************** 5. row *************************** id: 1 user_id: 1 old_score: 80 new_score: 95 change_value: 15 reason: 完善个人资料 created_at: 2025-11-09 05:38:14 5 rows in set (0.00 sec) mysql> SELECT user_id, score, level, updated_at FROM ecs_user_credit; +---------+-------+-----------------+---------------------+ | user_id | score | level | updated_at | +---------+-------+-----------------+---------------------+ | 1 | 90 | ★★★★★ | 2025-11-09 06:22:39 | | 2 | 90 | ★★★★☆ | 2025-11-09 06:22:39 | +---------+-------+-----------------+---------------------+ 2 rows in set (0.00 sec) mysql> CALL sp_add_credit(3, 10, '邀请好友'); Query OK, 1 row affected (0.00 sec) mysql> DELIMITER ;; mysql> DROP PROCEDURE IF EXISTS sp_add_credit;; Query OK, 0 rows affected (0.00 sec) mysql> CREATE PROCEDURE sp_add_credit( -> IN p_user_id INT, -> IN p_change INT, -> IN p_reason VARCHAR(100) -> ) -> BEGIN -> DECLARE current_score INT DEFAULT 80; -> DECLARE CONTINUE HANDLER FOR NOT FOUND SET current_score = 80; -> -> -- 尝试获取当前分数(如果存在) -> SELECT score INTO current_score -> FROM ecs_user_credit -> WHERE user_id = p_user_id -> FOR UPDATE; -> -> -- 插入或更新:不存在则从 80+p_change 开始 -> INSERT INTO ecs_user_credit (user_id, score) -> VALUES (p_user_id, current_score + p_change) -> ON DUPLICATE KEY UPDATE score = score + p_change; -> END;; Query OK, 0 rows affected (0.00 sec) mysql> DELIMITER ; mysql> DELIMITER ;; mysql> DROP PROCEDURE IF EXISTS sp_add_credit;; Query OK, 0 rows affected (0.00 sec) mysql> CREATE PROCEDURE sp_add_credit( -> IN p_user_id INT, -> IN p_change INT, -> IN p_reason VARCHAR(100) -> ) -> BEGIN -> DECLARE current_score INT DEFAULT 80; -> DECLARE new_score INT; -> DECLARE CONTINUE HANDLER FOR NOT FOUND SET current_score = 80; -> -> -- 获取当前分数(加锁) -> SELECT score INTO current_score -> FROM ecs_user_credit -> WHERE user_id = p_user_id -> FOR UPDATE; -> -> -- 计算新分数 -> SET new_score = current_score + p_change; -> -> -- 限制范围 -> IF new_score < 0 THEN -> SET new_score = 0; -> ELSEIF new_score > 100 THEN -> SET new_score = 100; -> END IF; -> -> -- 写入数据库 -> INSERT INTO ecs_user_credit (user_id, score) -> VALUES (p_user_id, new_score) -> ON DUPLICATE KEY UPDATE score = new_score; -> END;; Query OK, 0 rows affected (0.01 sec) mysql> DELIMITER ; mysql> CREATE OR REPLACE VIEW vw_user_credit_summary AS -> SELECT -> u.user_id, -> u.score, -> u.level, -> u.updated_at, -> ( -> SELECT GROUP_CONCAT(reason SEPARATOR '; ') -> FROM ecs_user_credit_log l -> WHERE l.user_id = u.user_id -> ORDER BY l.created_at DESC -> LIMIT 3 -> ) AS recent_actions -> FROM ecs_user_credit u -> ORDER BY u.score DESC; Query OK, 0 rows affected (0.01 sec) mysql> SELECT * FROM vw_user_credit_summary\G *************************** 1. row *************************** user_id: 1 score: 90 level: ★★★★★ updated_at: 2025-11-09 06:22:39 recent_actions: 完善个人资料; 评论被举报; 测试加分; 系统调整; 系统调整 *************************** 2. row *************************** user_id: 2 score: 90 level: ★★★★☆ updated_at: 2025-11-09 06:22:39 recent_actions: NULL *************************** 3. row *************************** user_id: 3 score: 90 level: ★★★★☆ updated_at: 2025-11-09 06:24:47 recent_actions: NULL 3 rows in set (0.00 sec) mysql> -- 日志表按用户和时间查询频繁 mysql> ALTER TABLE ecs_user_credit_log ADD INDEX idx_user_time (user_id, created_at); Query OK, 0 rows affected (0.02 sec) Records: 0 Duplicates: 0 Warnings: 0 mysql> mysql> -- 主表按分数排序常用 mysql> ALTER TABLE ecs_user_credit ADD INDEX idx_score (score); Query OK, 0 rows affected (0.03 sec) Records: 0 Duplicates: 0 Warnings: 0 mysql> CREATE PROCEDURE sp_add_credit(...) -> BEGIN -> DECLARE current_score INT DEFAULT 80; 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 '...) BEGIN DECLARE current_score INT DEFAULT 80' at line 1 mysql> DECLARE new_score INT; 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 'DECLARE new_score INT' at line 1 mysql> DECLARE CONTINUE HANDLER FOR NOT FOUND SET current_score = 80; 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 'DECLARE CONTINUE HANDLER FOR NOT FOUND SET current_score = 80' at line 1 mysql> mysql> SELECT score INTO current_score FROM ecs_user_credit WHERE user_id = p_user_id FOR UPDATE; ERROR 1327 (42000): Undeclared variable: current_score mysql> mysql> SET new_score = current_score + p_change; ERROR 1193 (HY000): Unknown system variable 'new_score' mysql> IF new_score < 0 THEN SET new_score = 0; END IF; 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 'IF new_score < 0 THEN SET new_score = 0' at line 1 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 'END IF' at line 1 mysql> IF new_score > 100 THEN SET new_score = 100; END IF; 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 'IF new_score > 100 THEN SET new_score = 100' at line 1 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 'END IF' at line 1 mysql> mysql> INSERT INTO ... ON DUPLICATE KEY UPDATE score = new_score; 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 '.. ON DUPLICATE KEY UPDATE score = new_score' at line 1 mysql> 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 'END' at line 1 ERROR: No query specified mysql> SELECT * FROM vw_user_credit_summary\G *************************** 1. row *************************** user_id: 1 score: 90 level: ★★★★★ updated_at: 2025-11-09 06:22:39 recent_actions: 完善个人资料; 评论被举报; 测试加分; 系统调整; 系统调整 *************************** 2. row *************************** user_id: 2 score: 90 level: ★★★★☆ updated_at: 2025-11-09 06:22:39 recent_actions: NULL *************************** 3. row *************************** user_id: 3 score: 90 level: ★★★★☆ updated_at: 2025-11-09 06:24:47 recent_actions: NULL 3 rows in set (0.00 sec) mysql> CREATE OR REPLACE VIEW vw_user_credit_summary AS -> SELECT -> u.user_id, -> u.score, -> u.level, -> u.updated_at, -> ( -> SELECT GROUP_CONCAT(reason SEPARATOR '; ') -> FROM ( -> SELECT reason -> FROM ecs_user_credit_log l -> WHERE l.user_id = u.user_id -> ORDER BY l.created_at DESC -> LIMIT 3 -> ) AS tmp -> ) AS recent_actions -> FROM ecs_user_credit u -> ORDER BY u.score DESC; ERROR 1054 (42S22): Unknown column 'u.user_id' in 'where clause' mysql> SET SESSION group_concat_max_len = 1024; Query OK, 0 rows affected (0.00 sec) mysql> ALTER TABLE ecs_user_credit_log ADD INDEX idx_user_time (user_id, created_at); ERROR 1061 (42000): Duplicate key name 'idx_user_time' mysql> ALTER TABLE ecs_user_credit ADD INDEX idx_score (score); ERROR 1061 (42000): Duplicate key name 'idx_score' mysql> -- 1. 备份数据 mysql> CREATE TABLE ecs_user_credit_backup AS SELECT * FROM ecs_user_credit; Query OK, 3 rows affected (0.04 sec) Records: 3 Duplicates: 0 Warnings: 0 mysql> mysql> -- 2. 删除旧表 mysql> DROP TABLE ecs_user_credit; Query OK, 0 rows affected (0.01 sec) mysql> mysql> -- 3. 重新创建带正确生成列的表 mysql> CREATE TABLE ecs_user_credit ( -> id INT AUTO_INCREMENT PRIMARY KEY, -> user_id INT NOT NULL UNIQUE, -> score INT DEFAULT 80, -> level VARCHAR(20) AS ( -> CASE -> WHEN score >= 95 THEN '★★★★★' -> WHEN score >= 85 THEN '★★★★☆' -> WHEN score >= 75 THEN '★★★☆☆' -> WHEN score >= 60 THEN '★★☆☆☆' -> ELSE '★☆☆☆☆' -> END -> ) STORED, -> updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP -> ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; Query OK, 0 rows affected (0.02 sec) mysql> INSERT INTO ecs_user_credit (id, user_id, score) -> SELECT id, user_id, score FROM ecs_user_credit_backup; Query OK, 3 rows affected (0.02 sec) Records: 3 Duplicates: 0 Warnings: 0 mysql> DROP TABLE ecs_user_credit_backup; Query OK, 0 rows affected (0.02 sec) mysql> SELECT user_id, score, level FROM ecs_user_credit; +---------+-------+-----------------+ | user_id | score | level | +---------+-------+-----------------+ | 1 | 90 | ★★★★☆ | | 2 | 90 | ★★★★☆ | | 3 | 90 | ★★★★☆ | +---------+-------+-----------------+ 3 rows in set (0.00 sec) mysql> CREATE OR REPLACE VIEW vw_user_credit_summary AS -> SELECT -> u.user_id, -> u.score, -> u.level, -> u.updated_at, -> ( -> SELECT GROUP_CONCAT(tmp.reason SEPARATOR '; ') -> FROM ( -> SELECT reason -> FROM ecs_user_credit_log l -> WHERE l.user_id = u.user_id -> ORDER BY l.created_at DESC -> LIMIT 3 -> ) AS tmp -> ) AS recent_actions -> FROM ecs_user_credit u -> ORDER BY u.score DESC; ERROR 1054 (42S22): Unknown column 'u.user_id' in 'where clause' mysql> ERROR 1061 (42000): Duplicate key name 'idx_user_time' -> ^C mysql> CREATE TABLE ecs_credit_rule ( -> action_code VARCHAR(50) PRIMARY KEY, -> description VARCHAR(100) NOT NULL, -> change_value INT NOT NULL, -> max_times_per_day INT DEFAULT 0 COMMENT '每日最多触发次数' -> ); Query OK, 0 rows affected (0.02 sec) mysql> mysql> INSERT INTO ecs_credit_rule VALUES -> ('register', '注册奖励', 10, 1), -> ('checkin', '签到', 2, 1), -> ('post', '发帖', 5, 3), -> ('report', '被举报', -10, 0); Query OK, 4 rows affected (0.01 sec) Records: 4 Duplicates: 0 Warnings: 0 mysql> DELIMITER ;; mysql> CREATE PROCEDURE sp_add_credit_by_action( -> IN p_user_id INT, -> IN p_action_code VARCHAR(50) -> ) -> BEGIN -> DECLARE v_change INT; -> DECLARE v_reason VARCHAR(100); -> -> -- 查询规则 -> SELECT change_value, description -> INTO v_change, v_reason -> FROM ecs_credit_rule -> WHERE action_code = p_action_code; -> -> -- 调用主过程 -> CALL sp_add_credit(p_user_id, v_change, v_reason); -> END;; Query OK, 0 rows affected (0.00 sec) mysql> DELIMITER ; mysql> CALL sp_add_credit_by_action(1, 'checkin'); Query OK, 2 rows affected (0.03 sec) mysql> -- 备份 mysql> CREATE TABLE ecs_user_credit_backup AS SELECT * FROM ecs_user_credit; Query OK, 3 rows affected (0.02 sec) Records: 3 Duplicates: 0 Warnings: 0 mysql> mysql> -- 删除旧表(清除被旧触发器污染的数据) mysql> DROP TABLE ecs_user_credit; Query OK, 0 rows affected (0.06 sec) mysql> mysql> -- 重建表:确保 level 是 STORED 生成列 mysql> CREATE TABLE ecs_user_credit (...); 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 '..)' at line 1 mysql> mysql> -- 恢复数据 mysql> INSERT INTO ecs_user_credit (id, user_id, score) SELECT id, user_id, score FROM ecs_user_credit_backup; ERROR 1146 (42S02): Table 'szrengjing_com.ecs_user_credit' doesn't exist mysql> mysql> -- 验证结果 mysql> SELECT user_id, score, level FROM ecs_user_credit; ERROR 1146 (42S02): Table 'szrengjing_com.ecs_user_credit' doesn't exist mysql> CREATE OR REPLACE VIEW vw_user_credit_summary AS -> SELECT -> u.user_id, -> ... -> ( -> SELECT GROUP_CONCAT(tmp.reason SEPARATOR '; ') -> FROM ( -> SELECT reason -> FROM ecs_user_credit_log l -> WHERE l.user_id = u.user_id -> ORDER BY l.created_at DESC -> LIMIT 3 -> ) AS tmp -> ) AS recent_actions -> FROM ecs_user_credit u; 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 '.. ( SELECT GROUP_CONCAT(tmp.reason SEPARATOR '; ') FROM ( ' at line 4 mysql> CREATE OR REPLACE VIEW vw_user_credit_summary AS -> SELECT -> u.user_id, -> u.score, -> u.level, -> u.updated_at, -> ( -> SELECT GROUP_CONCAT(log_entry.reason SEPARATOR '; ') -> FROM ( -> SELECT reason -> FROM ecs_user_credit_log l -> WHERE l.user_id = u.user_id -> ORDER BY l.created_at DESC -> LIMIT 3 -> ) AS log_entry -> ) AS recent_actions -> FROM ecs_user_credit u -> ORDER BY u.score DESC; ERROR 1146 (42S02): Table 'szrengjing_com.ecs_user_credit' doesn't exist mysql> CREATE OR REPLACE VIEW vw_user_credit_summary AS -> SELECT -> u.user_id, -> u.score, -> u.level, -> u.updated_at, -> ( -> SELECT GROUP_CONCAT(reason SEPARATOR '; ') -> FROM ( -> SELECT reason -> FROM ecs_user_credit_log -> WHERE user_id = u.user_id -> ORDER BY created_at DESC -> LIMIT 3 -> ) AS t -> ) AS recent_actions -> FROM ecs_user_credit u -> ORDER BY u.score DESC; ERROR 1146 (42S02): Table 'szrengjing_com.ecs_user_credit' doesn't exist mysql>
最新发布
11-10
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值