根本原因是mysql decimal字段未指定小数位(如decimal(10)默认numeric_scale=0),导致小数被截断;php端需用预处理绑定正确类型、避免float计算误差,并检查sql_mode与表结构。

MySQL字段定义为DECIMAL但PHP存入后变整数
根本原因通常是字段定义没指定小数位,比如建表写了 DECIMAL(10) 而不是 DECIMAL(10,2)。MySQL在未显式声明小数位时,默认小数位为0,所有小数部分会被截断或四舍五入为整数。
实操建议:
立即学习“PHP免费学习笔记(深入)”;
- 用
SHOW CREATE TABLE `table_name`查看实际字段定义,确认是否含小数位参数 - 修改字段:执行
ALTER TABLE `table_name` MODIFY COLUMN `price` DECIMAL(10,2); - 注意:修改过程中若已有数据含小数,且原字段是整型(如
INT),需先转成带精度的DECIMAL,否则小数丢失不可逆
PHP插入时小数被强制转整——检查mysqli_real_escape_string或PDO绑定类型
常见于手动拼SQL字符串时,把浮点变量直接拼进SQL,而PHP在字符串化过程中可能触发科学计数法或精度丢失;更隐蔽的是PDO预处理中未指定类型,导致PDO::PARAM_STR覆盖了数值精度。
实操建议:
立即学习“PHP免费学习笔记(深入)”;
- 避免字符串拼接数值:
"INSERT INTO t VALUES (" . $price . ")"→ 改用预处理 - PDO插入时显式绑定类型:
$stmt->bindValue(':price', $price, PDO::PARAM_STR);改为PDO::PARAM_STR仅当确定要字符串化;对金额优先用PDO::PARAM_STR或直接不传类型(让PDO自动推断) - 若用
mysqli,确保传入的是 float 类型值,而非字符串形式的数字(如"19.99"可能被当作字符串截断)
PHP浮点运算后存入MySQL精度异常——别依赖float/double做业务计算
PHP的 float 是IEEE 754双精度,本身存在二进制表示误差(如 0.1 + 0.2 !== 0.3)。若用 float 计算后再存入 DECIMAL(10,2),入库前可能已是 0.29999999999999999,MySQL按四舍五入规则存为 0.30 或截断为 0.29,取决于sql_mode设置。
实操建议:
立即学习“PHP免费学习笔记(深入)”;
- 金额类运算统一用字符串或整数(单位“分”):
$cents = (int)round($yuan * 100); - 必须用小数运算时,入库前格式化:
number_format($value, 2, '.', ''),再作为字符串传入预处理 - 检查MySQL的
sql_mode是否含STRICT_TRANS_TABLES,它会让超出精度的值报错而非静默截断
查字段长度与小数位的最快命令
别翻phpMyAdmin界面,直接用SQL定位问题字段:
SELECT COLUMN_NAME, DATA_TYPE, NUMERIC_PRECISION, NUMERIC_SCALE FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = 'your_db_name' AND TABLE_NAME = 'your_table_name' AND COLUMN_NAME = 'your_column_name';
NUMERIC_PRECISION 是总位数,NUMERIC_SCALE 是小数位数。如果 NUMERIC_SCALE 为 0 或 NULL,说明当前字段不存小数。
容易被忽略的一点:有些ORM(如Laravel Eloquent)在迁移中写 $table->decimal('price') 默认生成 DECIMAL(8,2),但若手动改过迁移又没跑 php artisan migrate:fresh,旧表结构不会自动更新。











