Delphi 开发避坑终极指南:数据库 Decimal (18,6) 类型选择,别再用错 Double 和 Currency!

一、前言

做 Delphi 业务系统、ERP、金融、交易、支付相关开发时,一定会遇到:

数据库字段:decimal(18,6) 问题:Delphi 端应该用什么类型接收?

网上常见错误答案:

  • 用 Double(精度隐患)
  • 用 Currency(直接丢数据)
  • 很少有人提到真正标准的 TBcd

本文结合实战 + 精度原理,给出最正确、最安全、工业级方案。


二、先明确:decimal (18,6) 是什么?

  • 总长度:18 位数字
  • 小数固定:6 位
  • 要求:绝对精确、不能四舍五入、不能丢位
  • 典型场景:金额、费率、汇率、重量、交易金额、第三方接口数据

这种数据绝对不能用不精确类型


三、致命错误:千万不要用 Currency

很多人被名字误导:

"Currency 是货币类型,存金额最安全!"

大错特错!

Currency 真相

  • 固定 4 位小数
  • 底层:Int64 / 10000
  • 存入 6 位小数 → 强制四舍五入到第 4 位

示例

plaintext

复制代码
数据库:123.456789
Currency 存储:123.4568

后两位小数直接丢失,永久无法恢复!

这不是精度问题,是数据损坏

结论decimal(18,6) 场景 严禁使用 Currency


四、勉强能用:Double 比 Currency 好,但不推荐

客观事实:Double 确实比 Currency 好很多

原因:

  • Double 能保存 15~16 位有效数字
  • 不会截断 6 位小数
  • 但它是二进制浮点数,天生精度误差

例如:

plaintext

复制代码
0.1 + 0.2 = 0.3000000000000001

结论

  • 临时、非核心数据可以用
  • 金融、金额、交易、高精度业务 严禁使用

五、正确方案 1:Int64(交易 / 支付 工业标准)

这是你提到的最小单位法,也是微信支付、支付宝、银联、交易接口通用标准:

把数值 ×1000000 用整数存储

示例:

plaintext

复制代码
123.456789 → 存储为 123456789(Int64)

优点

  • ✅ 100% 精确,无任何精度丢失
  • ✅ 完美匹配 6 位小数
  • ✅ 整数运算极快
  • ✅ 跨语言、跨系统无歧义

Delphi 代码模板

delphi

复制代码
const
  SCALE = 1000000; // 6 位小数放大倍数
var
  Price: Int64;
begin
  // 从数据库读取
  Price := Round(DataSet['price'].AsFloat * SCALE);

  // 计算(全整数,绝对精确)
  Price := Price + 100000; // +0.100000

  // 显示
  Caption := FormatFloat('0.000000', Price / SCALE);
end;

六、正确方案 2:TBcd(Delphi 官方正统首选)

重点来了!Delphi 原生专门对应数据库 decimal 的精确类型:TBcd

单元:

delphi

复制代码
Data.FmtBcd

TBcd 是什么?

  • 数据库 decimal/numeric原生内存结构
  • 100% 精确十进制
  • 支持任意精度(完美支持 18,6)
  • 无浮点误差
  • TBCDField 底层就是 TBcd

实战代码

delphi

复制代码
uses Data.FmtBcd;

var
  A, B, C: TBcd;
begin
  // 赋值
  A := StrToBcd('123.456789');
  B := StrToBcd('456.987654');

  // 精确运算
  C := BcdAdd(A, B);  // 加
  C := BcdSub(A, B);  // 减
  C := BcdMul(A, B);  // 乘
  C := BcdDiv(A, B);  // 除

  // 显示
  Caption := BcdToStr(C);
end;

数据库直接读取(零损耗、最标准)

delphi

复制代码
var
  Value: TBcd;
begin
  Value := DataSet['price'].AsBcd;
end;

七、TBcd vs Int64 怎么选?

两个都是 100% 精确 正确方案!

选 TBcd

  • 标准业务系统、ERP、管理系统
  • 大量数据库操作
  • 希望代码最规范、最简单
  • 不想手动缩放(×1000000)

选 Int64

  • 支付、交易、对接第三方接口
  • 跨语言、跨平台
  • 追求极致性能
  • 习惯最小单位设计

八、终极推荐排名(永不踩坑)

针对 decimal(18,6)

  1. 🥇 TBcd(Data.FmtBcd) 官方标准、100% 精确、完美匹配→ 业务系统首选

  2. 🥈 Int64 交易 / 支付标准、极快、精确→ 接口 / 交易系统首选

  3. 🥉 Double有精度风险,仅临时凑合→ 不推荐用于核心数据

  4. ❌ Currency 固定 4 位小数,直接丢失 2 位数据→ 绝对禁用


九、总结(金句)

  1. Delphi 处理 decimal(18,6)只有 TBcd 和 Int64 是正确方案
  2. Currency 固定 4 位小数,会直接损坏 6 位数据
  3. Double 有精度隐患,只能算备胎
  4. 业务系统用 TBcd,交易接口用 Int64
  5. 固定小数位 = 精确类型 = 行业标准,绝不妥协!

十、结束语

精度问题在金融、交易、金额类系统中是红线问题。希望这篇文章能帮你避开 Delphi 中最常见的数值类型坑。

如果你也在做高精度计算、金额计算、对接支付接口,欢迎点赞、收藏、关注!

相关推荐
techdashen2 小时前
一个徽章坏了,顺带扯出了 2.3 万个 feature
数据库·mysql
2301_814809862 小时前
CSS Grid布局如何解决图片溢出网格单元_设置object-fit与网格尺寸.txt
jvm·数据库·python
魂梦翩跹如雨2 小时前
数据库的“契约” —— 约束(Constrains)
java·数据库·mysql
m0_678485452 小时前
如何在Bootstrap中自定义Modal的弹出动画效果
jvm·数据库·python
与衫2 小时前
[特殊字符] 解决 DataHub 无法解析复杂 SQL 血缘的问题(gsp-datahub-sidecar 实测)
数据库·sql
m0_493934532 小时前
CSS如何禁止子元素浮动影响父级_设置父容器BFC属性
jvm·数据库·python
weixin_586061462 小时前
Golang怎么安装和配置开发环境_Golang环境搭建完整教程【总结】
jvm·数据库·python
m0_493934532 小时前
html标签怎么避免标签嵌套错误_div不能放在p内原因【详解】
jvm·数据库·python
2301_782659183 小时前
Go语言goroutine调度原理_Go语言GMP调度模型教程【高效】
jvm·数据库·python