必须显式声明DECIMAL(M,D)并全程保持类型链完整,否则隐式转DOUBLE会导致精度丢失;漏写(M,D)语法报错,传参用100.0而非100,运算中任一环节断裂都会引发连锁漂移。

DECIMAL 类型没用对,或者根本没用 —— 这是函数内浮点数精度偏差的根源。
函数参数和变量必须显式声明 DECIMAL(M,D)
MySQL 函数里只要出现 FLOAT 或 DOUBLE,就等于给精度埋雷。哪怕你只临时算个折扣率,也得写成:DECLARE rate DECIMAL(12,6);✅DECLARE total DECIMAL;❌(语法报错)DECLARE total DECIMAL(10);❌(缺标度,仍报错)
漏掉 (M,D) 就不是声明,是语法错误;M 是总位数,D 是小数位数,二者都不可省——DECIMAL(15,2) 能存 9999999999999.99,DECIMAL(12,6) 适合汇率类场景。
调用时传 100.0 比传 100 安全得多
函数参数声明再严谨,调用时传裸数字也会触发隐式转换:
• CALL calc(100, 0.08); ❌ 0.08 被当 DOUBLE,中间乘法结果大概率漂移
• CALL calc(100.0, 0.08); ✅ 末尾加 .0 是最轻量的 DECIMAL 提示
• CALL calc(CAST(100 AS DECIMAL(10,2)), CAST(0.08 AS DECIMAL(5,4))); ✅ 最稳妥,但写法重
MySQL 不会警告,也不会报错,它只是默默把 0.1 + 0.2 算成 0.30000000000000004,然后塞进你的返回值里。
运算链中任意一环断掉,后续全漂
DECIMAL 运算本身不丢精度,但类型链断裂就会连锁失准:
• SELECT 100 / 3; → 返回 DOUBLE,值约 33.333333333333336
• SELECT CAST(100 AS DECIMAL(10,2)) / CAST(3 AS DECIMAL(10,2)); → 返回 DECIMAL(22,14),值为 33.33333333333333
• 两个 DECIMAL(10,2) 相乘,结果是 DECIMAL(20,4);若你用 DECIMAL(10,2) 变量接,会静默截断(如 123.4567 → 123.46),不报错也不提示
ROUND()、SUM() 看似能补救,但它们作用在已失准的值上,属于“修图”而非“拍对”。
FLOAT 声明、裸数字传参、隐式转 DOUBLE 运算,最后给你一个“看起来对”的错值——尤其在批量计算时,偏差会累积放大,而日志里连 warning 都没有。


















