严格模式下sysdate()在子查询中报错,因其被判定为非确定性函数;可用now()替代或会话级临时关闭严格模式,但需谨慎评估业务逻辑对时间精度的真实需求。
mysql 严格模式开启时,sysdate()、now()、curdate() 等函数在某些子查询或视图定义里会被拒绝——这不是函数本身有问题,而是严格模式对“不确定函数”的执行上下文做了限制。
为什么 sysdate() 在子查询里报错
MySQL 严格模式(尤其是 STRICT_TRANS_TABLES + NO_UNSIGNED_SUBTRACTION 组合)会强化对“非确定性函数”的使用约束。当这些函数出现在 WHERE 子句的子查询、派生表或视图定义中时,MySQL 可能判定其结果不可预测(比如 sysdate() 每次调用都可能不同),从而拒绝执行。
常见错误信息:ERROR 1064 (42000): You have an error in your SQL syntax; ... This function has none of DETERMINISTIC, NO SQL, or READS SQL DATA...
- 该限制和函数是否真被用作计算无关,只和 MySQL 的“确定性声明”校验逻辑有关
- 即使你只是
SELECT sysdate() FROM (SELECT 1) t,也可能触发 -
now()和sysdate()行为不同:前者在语句开始时固定,后者实时变化,后者更容易被标为“非确定”
临时绕过:用 SET sql_mode 动态关闭严格检查
不改全局配置的前提下,可以在会话级临时放宽限制,适合调试或特定查询场景。
- 执行前加:
SET sql_mode = '';或SET sql_mode = 'NO_ENGINE_SUBSTITUTION'; - 注意:必须在同一会话中先执行
SET,再执行含sysdate()的查询,不能跨连接 - 如果应用使用连接池,需确认每次获取连接后是否重置了
sql_mode(很多 ORM 默认不重置) - 不推荐长期依赖此方式,因为会掩盖其他潜在的数据完整性风险
长期解法:显式声明函数确定性或换用等价确定表达式
更稳妥的方式是避免让 MySQL 对函数做“确定性推断”,直接提供它能接受的替代方案。
- 用
now()替代sysdate():多数场景下语义足够,且now()默认被 MySQL 视为“语句级确定” - 在视图或存储过程中,对函数加
DETERMINISTIC声明(仅限自定义函数,系统函数无法修改) - 若只需日期部分,改用
CURDATE()—— 它在大多数 MySQL 版本中被默认标记为DETERMINISTIC - 极端情况可预计算时间值:在应用层生成
DATE(NOW())字符串传入,避开 SQL 解析阶段的校验
检查与验证当前 sql_mode 配置
别猜,直接查。不同环境(开发/测试/生产)的 sql_mode 往往不一致,这是问题复现难的根本原因。
- 查会话级:
SELECT @@sql_mode; - 查全局级:
SELECT @@global.sql_mode; - 重点看是否包含
STRICT_TRANS_TABLES、STRICT_ALL_TABLES、NO_ZERO_DATE等组合项 - MySQL 8.0+ 默认启用严格模式,5.7 则取决于安装选项,升级后容易突然暴露这类问题
真正麻烦的不是改配置,而是那些隐式依赖 sysdate() 实时性的业务逻辑——它们在严格模式下看似跑通,实则可能因优化器重写或并行执行产生意外交互。动手前,先确认你到底需要“语句开始时间”还是“执行到此刻的时间”。











