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

为何向无符号整数列插入负数未得到列类型最大值?

关于MySQL无符号整数溢出与截断的疑问解答

1. “此类操作”具体指什么?

文档中的“此类操作”特指导致结果超出无符号整数类型范围的运算或赋值操作,核心包含两种场景:

  • 无符号整数参与的算术运算(尤其是减法)产生负数结果(比如0 UNSIGNED - 1),默认会被转换为对应无符号类型的最大值(如BIGINT UNSIGNED的18446744073709551615)。
  • 直接向无符号整数列插入低于其最小值(0)的数值(比如向tinyint unsigned列插入-2)。

你提到的“整数间相减,若其中一个为UNSIGNED类型,默认结果为无符号值”是正确的,这类减法若得到负数,就属于触发截断规则的“此类操作”。

2. 为什么插入-2到tinyint unsigned列得到0而非254?

这是因为MySQL对直接插入字面量负数和无符号算术溢出结果的处理逻辑完全不同:

  • 直接插入-2这类字面量负数到无符号列时,MySQL判定为“值低于列的最小值(0)”,在默认sql_mode(不含严格模式)下,会将值截断到列的最小值0——这和C语言的补码循环转换逻辑不同。
  • 只有插入无符号算术运算的溢出结果时,才会触发“截断为列类型最大值”的规则。比如CAST(0 AS UNSIGNED) - 1的结果是BIGINT UNSIGNED的最大值18446744073709551615,插入tinyint unsigned列时,MySQL会取该值的低8位(二进制全1),最终得到tinyint unsigned的最大值255,而非你预期的254。

3. “结果被截断为该列类型的最大值”的具体含义

这条规则仅针对无符号算术运算产生的溢出值(即负数被转换为超大无符号值的情况):

  • 当运算结果是大尺寸无符号类型(如BIGINT UNSIGNED)且超出目标无符号列范围时,MySQL会对结果进行按位截断,取与目标列位数一致的低N位,最终得到的值就是目标列的最大值(比如tinyint unsigned是8位,低8位全1对应255)。
  • 若启用NO_UNSIGNED_SUBTRACTION,无符号减法的结果会被视为有符号负数,此时插入无符号列会截断到0,而非最大值。

4. 你的测试问题排查

你在默认sql_mode下的测试结果符合MySQL规则:

  • INSERT INTO test (uti) VALUES (-2); 得到0:属于直接插入低于最小值的数值,触发最小值截断。
  • INSERT INTO test (uti) VALUES ((SELECT CAST(0 AS UNSIGNED) - 1)); 应得到255而非溢出报错:默认sql_mode下无符号算术溢出不会报错,而是转换为超大无符号值,插入时按位截断到列的最大值。如果你的结果不符,检查是否开启了严格模式(如STRICT_TRANS_TABLES),此时会直接报错而非截断。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 01:20:36