MariaDB EVENT事件中使用游标循环出现语法错误如何解决?
问题根因排查
- 报错1:
BEGIN附近语法错误:默认SQL语句分隔符为;,事件体内的语句包含;时会被编译器提前判定为语句结束,导致结构不完整 - 报错2:
delimiter $$附近语法错误:你使用的数据库管理工具(如Navicat、phpMyAdmin、部分云数据库控制台)内置了语句分隔符处理逻辑,不支持手动执行DELIMITER命令,手动写反而会触发语法报错
前置配置
首先开启事件调度器,否则事件不会触发执行:
-- 临时开启(重启MySQL后失效) SET GLOBAL event_scheduler = ON; -- 永久生效需要修改my.cnf/my.ini配置文件,在[mysqld]段下添加 -- event_scheduler = ON
正确实现代码
场景1:命令行执行(需要手动修改分隔符)
DELIMITER $$ CREATE EVENT IF NOT EXISTS `lifeinsurance_reset` ON SCHEDULE EVERY 1 HOUR STARTS CURRENT_TIMESTAMP ON COMPLETION PRESERVE ENABLE DO BEGIN -- 关联更新:仅扣除银行余额>=25000的角色费用,同时延后续费日期 UPDATE life_insurance li INNER JOIN `characters` c ON li.character_id = c.id SET c.bank_balance = c.bank_balance - 25000, li.renewal_date = DATE_ADD(li.renewal_date, INTERVAL 1 MONTH) WHERE li.renewal_date <= NOW() AND c.bank_balance >= 25000; -- 可选:如果需要处理余额不足的记录,可以额外加更新逻辑标记逾期状态 -- UPDATE life_insurance SET is_overdue = 1 WHERE renewal_date <= NOW() AND character_id NOT IN (SELECT id FROM `characters` WHERE bank_balance >=25000); END $$ DELIMITER ;
场景2:数据库管理工具(Navicat/phpMyAdmin等)执行(不需要写DELIMITER)
直接执行以下代码即可:
CREATE EVENT IF NOT EXISTS `lifeinsurance_reset` ON SCHEDULE EVERY 1 HOUR STARTS CURRENT_TIMESTAMP ON COMPLETION PRESERVE ENABLE DO BEGIN UPDATE life_insurance li INNER JOIN `characters` c ON li.character_id = c.id SET c.bank_balance = c.bank_balance - 25000, li.renewal_date = DATE_ADD(li.renewal_date, INTERVAL 1 MONTH) WHERE li.renewal_date <= NOW() AND c.bank_balance >= 25000; END
字段说明
- 代码中默认两张表关联字段为
life_insurance.character_id关联characters.id,characters表银行余额字段为bank_balance,如果你的表字段名不同,替换为实际字段即可 - 事件默认创建后永久生效,每小时执行一次
- 加了余额校验逻辑,避免扣成负数,如果不需要校验可以删除
AND c.bank_balance >= 25000条件
内容的提问来源于stack exchange,提问作者AdamJames
相关产品推荐
相关产品推荐

