MySQL Server 5.7(InnoDB Cluster)中添加依赖其他列的DATE列时的语法错误问题排查
解决MySQL 5.7中添加依赖其他列的DATE类型自动更新列的问题
咱们先拆解下你遇到的两个核心问题,以及对应的解决方案:
1. 为什么DEFAULT+ON UPDATE的方式行不通?
MySQL的DEFAULT和ON UPDATE子句有个严格限制:它们不能引用表内的其他列。你用CURRENT_TIMESTAMP没问题,因为这是不依赖表数据的系统函数,但ADDDATE(order_loaded_on, ...)用到了同表的order_loaded_on和delivery_time列,这种依赖表内列的表达式是不允许出现在DEFAULT或ON UPDATE里的,所以第一次执行语句时会报语法错误;哪怕去掉ON UPDATE能执行,也只能在插入时计算一次,后续其他列变更时不会自动更新,这显然不符合你的需求。
2. 生成列的语法错误原因及正确写法
你尝试用生成列的思路是对的,但MySQL 5.7对生成列的语法有个强制要求:必须显式声明是VIRTUAL还是STORED类型(MySQL 8.0及以后默认是VIRTUAL,但5.7不支持隐式声明),这就是你语句报错的关键原因。
针对你的需求,正确的生成列语句应该是这样的(对应你后来用的意大利语列名):
ALTER TABLE CrmContratto ADD COLUMN PrevistaConsegna DATE GENERATED ALWAYS AS (ADDDATE(DataCaricamentoOrdine, INTERVAL FLOOR(TempiConsegna * 1.4) DAY)) VIRTUAL; -- 或者替换为 STORED,根据你的性能需求选择
关于VIRTUAL和STORED的区别:
- VIRTUAL:这列不会实际存储在磁盘上,每次查询时才计算值,优点是节省存储空间,适合查询频率不极高的场景;当
DataCaricamentoOrdine或TempiConsegna变更时,查询该列会自动计算最新值。 - STORED:这列的值会存储在磁盘上,当依赖的列变更时,MySQL会自动重新计算并更新该列的值,优点是查询时不需要计算速度更快,但会占用额外的存储空间。
另外要确认你的表达式是确定性的——也就是给定相同的DataCaricamentoOrdine和TempiConsegna,结果永远一致,你的ADDDATE(...)+FLOOR(...)完全符合这个要求,所以可以正常作为生成列的表达式。
总结
放弃DEFAULT+ON UPDATE的方案,改用显式声明类型的生成列,就能实现你需要的“值依赖其他列且自动更新”的DATE类型列了。
内容的提问来源于stack exchange,提问作者user16788546
相关产品推荐
相关产品推荐

