You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MariaDB中BIGINT UNSIGNED越界异常的奇怪行为求助

问题分析与解释

这个问题的核心是MariaDB的数值类型自动推导规则和不同整数类型的范围限制在起作用,咱们一步步拆解:

1. 为什么19位减数会触发报错?

首先,UNIX_TIMESTAMP()在MariaDB 10.1+版本中返回的是有符号BIGINT(范围:-9223372036854775808 到 9223372036854775807,约±9e18)。

当你执行SELECT UNIX_TIMESTAMP() - 9999999999999999999;时:

  • 减数9999999999999999999是19位正整数,刚好超过了有符号BIGINT的最大值(9e18),所以MariaDB会自动将它判定为BIGINT UNSIGNED(范围:0到18446744073709551615,约1.8e19)。
  • 默认情况下,当有符号和无符号整数混合运算时,MariaDB会强制将结果转为无符号BIGINT。而当前时间戳(比如约1.7e9)减去1e19的结果是负数,无符号BIGINT无法存储负数,因此触发ERROR 1690 (22003)的范围溢出错误。

为什么设置sql_mode=NO_UNSIGNED_SUBTRACTION也没用?

这个模式的作用是:当有符号和无符号操作数相减时,优先将结果转为有符号BIGINT。但问题在于,你的减数9999999999999999999本身已经超过了有符号BIGINT的最大值,无法被存储为有符号整数,所以MariaDB仍然会将它视为无符号类型,运算结果还是会被强制转为无符号,导致报错。

2. 为什么其他情况能正常执行?

情况一:减数为18位或20位数字

  • 18位减数:比如999999999999999999(约1e18),这个数值在有符号BIGINT的范围内,所以会被判定为有符号BIGINT。两个有符号整数相减,结果也是有符号BIGINT,即使是负数也能正常存储,因此查询正常。
  • 20位减数:比如99999999999999999999(约1e20),这个数值超过了BIGINT UNSIGNED的最大值,MariaDB会自动将它转为DECIMAL类型(支持更大的数值范围)。此时UNIX_TIMESTAMP()(有符号BIGINT)和DECIMAL运算,结果会转为DECIMAL,DECIMAL支持存储负数,所以不会报错。

情况二:用加法替代减法(SELECT UNIX_TIMESTAMP() + -9999999999999999999;)

这里的-9999999999999999999是负数,它的绝对值超过了有符号BIGINT的最大值,所以MariaDB会将它转为DECIMAL类型。当有符号BIGINT和DECIMAL做加法运算时,结果会被转为DECIMAL,DECIMAL可以存储这个负数结果,因此查询正常返回。

解决建议

如果需要稳定执行这类跨范围的减法运算,可以手动将操作数转为DECIMAL类型,避免类型推导的问题:

SELECT CAST(UNIX_TIMESTAMP() AS DECIMAL) - 9999999999999999999;

内容的提问来源于stack exchange,提问作者user11669458

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.09 15:47:28