
Laravel 项目中保存小数(如 quantity=20.10)时数据库却只存入整数(20),根本原因通常是字段类型不匹配——需将数据库列明确定义为 DECIMAL(p,s) 并确保 PHP 层不发生隐式类型转换。
laravel 项目中保存小数(如 quantity=20.10)时数据库却只存入整数(20),根本原因通常是字段类型不匹配——需将数据库列明确定义为 `decimal(p,s)` 并确保 php 层不发生隐式类型转换。
在 Laravel(或基于 CodeIgniter 的类似项目,如问题中所示)中,数值被“自动取整”并非框架本身行为,而是底层数据库字段定义与数据传递过程协同失配所致。核心问题往往出在两处:数据库列类型不支持小数存储,以及PHP 层未保留原始数值精度。
✅ 正确的数据库字段定义
必须将 quantity 字段修改为 DECIMAL 类型(而非 INT、FLOAT 或 VARCHAR):
ALTER TABLE `pur_order_detail` MODIFY COLUMN `quantity` DECIMAL(10,2) NOT NULL DEFAULT '0.00';
-
DECIMAL(10,2)表示最多 10 位数字,其中 2 位为小数(如9999999.99); - 避免使用
FLOAT/DOUBLE:它们是近似值类型,存在二进制浮点误差(如20.10可能存为20.099999999999998),且 Laravel/MySQL 在某些配置下会隐式四舍五入; - 绝对不要用
VARCHAR存数值:虽能“显示”小数,但丧失数值运算能力、索引效率与数据完整性约束。
? 提示:可通过
SHOW COLUMNS FROM pur_order_detail LIKE 'quantity';验证当前字段类型。
✅ PHP 层保持数值原始精度
检查你的 $es_detail 数组中 quantity 值是否在插入前已被强制转为整型或截断。例如以下代码存在隐患:
// ❌ 危险:若 $pur_order_detail[$i] 来自表单字符串(如 "20.10"),直接赋值可能被弱类型转换影响 $rq['quantity'] = $pur_order_detail[$i]; // 若后续未明确 cast,可能丢失精度 // ✅ 推荐:显式转换为 float 或 string(推荐 string,避免浮点误差) $rq['quantity'] = (string) round((float)$pur_order_detail[$i], 2); // 保留两位小数 // 或更安全地——从原始输入解析后直接作为字符串传入 $rq['quantity'] = trim($pur_order_detail[$i]); // 确保无空格,且未被 intval() 等函数处理
同时,请确认 reformat_currency_pur() 和 to_sql_date() 等辅助函数不会对数值字段做非预期的类型转换(例如内部调用了 (int) 强转)。
✅ Laravel 模型层补充建议(如迁移到 Eloquent)
若未来升级为标准 Laravel Eloquent 模型,可在模型中启用 casts 保证精度:
protected $casts = [
'quantity' => 'decimal:2',
'unit_price' => 'decimal:2',
'total_money' => 'decimal:2',
];该配置会自动将属性序列化为 string 或 float(取决于 decimal cast 实现),并配合 DECIMAL 字段实现端到端精度保障。
⚠️ 注意事项总结
- 不要依赖
FLOAT类型存储业务关键小数(如数量、单价、金额); - 所有涉及计算的字段(
quantity,unit_price,into_money,total_money)均应统一设为DECIMAL; - 插入前用
var_dump($es_detail)检查实际传入值是否仍为"20.10"或20.1,排除 PHP 层提前截断; - 使用
DB::table()->insert()或insertBatch()时,确保数组值为标量(非对象/资源),且未被 Laravel 自动类型推断干扰。
修复后,20.10 将原样写入数据库,并可正确参与 SUM()、WHERE quantity > 20 等数值查询与聚合操作——这才是健壮财务/进销存系统应有的数据基础。


















