位置:首页 > SQL > SQL 插入小数后精度丢失怎么办

SQL 插入小数后精度丢失怎么办

时间:2026-08-23  |  作者:怪兽小助手  |  阅读:0

导致问题的根本原因是精度丢失,并非数据损坏。具体来说,SQL Server的money字段因JDBC驱动忽略scale,MySQL变量未声明精度,MyBatis批量插入时取最小scale,PostgreSQL/Oracle误用浮点类型,这些情况都会致使小数位被截断或计算出现失准的现象。

SQL插入小数后精度丢失怎么办

直接原因通常是数据库字段类型没配对、JDBC驱动没传精度、或者SQL里写了裸数字触发隐式转换——不是数据“坏了”,而是中间某一层悄悄把它当整数或浮点数处理了。

SQL Server 插入时 money 字段丢小数位

SQL Server的money类型比较特殊,它本质上是固定的DECIMAL(19,4)。然而,JDBC驱动(尤其是旧版本)并不认识这个类型。当使用setBigDecimal方法时,它会直接忽略scale参数。因此,BigDecimal(35.35, scale=2)会被当作35插入到数据库中。

  • 临时解法:改用标准 DECIMAL(p,s) 字段,比如 DECIMAL(18,2)
  • 驱动层补救:升级 mssql-jdbc 到 9.4+,连接串加参数 calcBigDecimalPrecision=true
  • MyBatis 显式声明:在 XML 中给参数加 jdbcType=DECIMALnumericScale=2,例如 #{item.amount, jdbcType=DECIMAL, numericScale=2}
  • 绕过驱动:SQL 层强制 cast,如 cast(#{item.amount} as decimal(18,2)) —— 这招在批量插入时最稳

MySQL 存储过程/函数里小数计算失准

哪怕字段定义是 DECIMAL(15,2),只要函数里用了 DECLARE total DECIMAL; 或调用时传 100 而不是 100.0,MySQL 就会按 DOUBLE 解析,中间一算就漂移。

  • 变量声明必须带精度:写成 DECLARE amount DECIMAL(15,2);,不能省略 (M,D)
  • 调用时字面量加 .0:用 CALL calc(100.0, 0.08); 替代 CALL calc(100, 0.08);
  • 运算链全程保 DECIMAL:所有参与计算的值都显式 CAST(... AS DECIMAL(15,2)),别依赖自动推导
  • 注意 SUM() 默认返回 DECIMAL(10,0):要精度就得 SUM(CAST(amount AS DECIMAL(15,2)))

MyBatis 批量插入时统一截断

MyBatis 对同一批参数会取最小公因数式精度——如果列表里有个 amount=100(scale=0)、另一个 amount=99.99(scale=2),驱动可能全按 scale=0 处理,导致后者变 99

  • XML 中每个数值参数都加 jdbcTypenumericScale,不靠默认映射
  • 更彻底:在 SQL 层 cast,例如 cast(#{item.gljyje} as decimal(22,6)),把精度控制收在 SQL 里
  • 避免混用:列表里别掺整数和小数,统一转成带小数位的 BigDecimal 再传
  • 验证手段:开启 MyBatis STDOUT_LOGGING,看日志里 bind 的参数是否带 scale 信息

PostgreSQL / Oracle 的 REAL/DIRECTIVE 类型陷阱

REALDOUBLE PRECISION 是 IEEE 754 浮点,0.1 + 0.2 存进去就是 0.30000000000000004,这不是 bug,是设计如此。

  • 财务、计费、配置类字段,一律用 NUMERIC(p,s)NUMBER(p,s),别碰 FLOAT 系列
  • 已有 REAL 字段?别指望修数据,得改表结构:ALTER TABLE t ALTER COLUMN col TYPE NUMERIC(12,4) USING col::NUMERIC(12,4);
  • BI 工具里看到的“对不上”,先查数据库原值:SELECT col::TEXT FROM t,如果文本显示 19.999999,说明存储层已失真
  • 应用层接收时,Ja va 用 BigDecimal,Python 用 decimal.Decimal,别用 float

真正容易被忽略的,是那个没加 .0 的除数、那个没声明标度的 DECIMAL 变量、还有 MyBatis 里没显式写的 numericScale——它们不会报错,只是默默把 35.35 变成 35。

免责声明:文中图文均来自网络,如有侵权请联系删除,心愿游戏发布此文仅为传递信息,不代表心愿游戏认同其观点或证实其描述。

相关文章

更多

精选合集

更多

大家都在玩

热门话题

大家都在看

更多