SQL中数值溢出和隐式转换易致静默数据失真:整数溢出可能截断或取模,浮点计算引发精度丢失,字符串转数值行为不一,跨库迁移存在类型语义差异;须启用严格模式、选合适类型、显式CAST、参数化查询及迁移前校验。
SQL中数值溢出和隐式转换不是报错就完事,而是可能静默截断、四舍五入或转成错误类型,导致数据失真却难以察觉。
例如 SQL Server 中 tinyint 范围是 0–255。若插入 300,默认会报错(ANSI_WARNINGS ON 时),但若关闭该选项或在某些兼容模式下,可能静默转为 300 % 256 = 44;MySQL 的 strict mode 关闭时,tinyint 插入 300 会自动变成 255(上限截断)。这种行为取决于数据库引擎+SQL模式,不能依赖默认表现。
把 DECIMAL(10,2) 字段和一个 FLOAT 变量参与计算时,数据库常将 DECIMAL 隐式转为 FLOAT 再运算——而 FLOAT 是二进制近似存储,0.1 + 0.2 ≠ 0.3 这类问题立刻复现。更隐蔽的是,某些 ORM 或中间件传参时自动把数字转成 double 再塞进参数化查询,源头已失真。
WHERE price = '99.99' 看起来没问题,但数据库需把字符串隐式转为数值类型。若字段是 DECIMAL(5,2),而传入的是 '999.999',部分数据库会截断小数(保留两位)、部分四舍五入、部分直接报错——行为不一致且不可控。更糟的是,'1e2'、' 123 '、'123abc' 在不同系统中解析结果差异极大。
、小数位标准化)从 MySQL 迁移到 PostgreSQL,INT 看似一样,但 MySQL 的 INT 默认是 signed(-2147483648 ~ 2147483647),PostgreSQL 的 INT 也是 4 字节有符号,看似兼容——可一旦原库用了 INT UNSIGNED(0 ~ 4294967295),迁过去就会溢出报错或被强转为负数。同理,Oracle 的 NUMBER(10) 和 SQL Server 的 NUMERIC(10,0) 表示范围相同,但隐式转换规则完全不同。
不复杂但容易忽略:一次隐式转换、一个未设限的 tinyint、一条没开 strict mode 的 insert,都可能让百万级数据悄然失真。