MySQL的TRUNCATE是DDL命令,不可截小数;PostgreSQL和SQL Server支持TRUNCATE(value,decimals)数值截断。MySQL需用TRUNCATE()函数(非DDL)、FLOOR缩放或CAST转DECIMAL,三者对负数和精度处理不同。

TRUNCATE 函数在 MySQL 和 PostgreSQL 中行为完全不同
别直接套用,TRUNCATE 在 MySQL 里是 DDL 命令(清空表),根本不能截小数;只有 PostgreSQL 和 SQL Server 支持 TRUNCATE(value, decimals) 这种数值截断用法。MySQL 用户真想截断小数,得换函数。
- MySQL:用
TRUNCATE()会报错ERROR 1142 (42000): TRUNCATE command denied to user(权限错误)或直接语法报错——因为它只认表名,不认数字 - PostgreSQL:支持
TRUNCATE(3.14159, 2)→3.14,且不四舍五入,纯截断 - SQL Server:也支持
TRUNCATE(value, length),但参数顺序和 PostgreSQL 一致
MySQL 正确截断小数的三种写法及区别
MySQL 没有原生 TRUNCATE 数值函数,但有三个可选方案:TRUNCATE()(名字巧合)、FLOOR() 配合缩放、CAST() 强转。它们处理负数、边界值时表现不同。
-
TRUNCATE(3.999, 2)→3.99;TRUNCATE(-3.999, 2)→-3.99(注意:这是 MySQL 里唯一叫TRUNCATE的数值函数,但容易和 DDL 混淆) -
FLOOR(3.999 * 100) / 100→3.99;但FLOOR(-3.999 * 100) / 100→-4.00(负数向下取整,不是截断) -
CAST(3.999 AS DECIMAL(10,2))→3.99;但超出精度会四舍五入:CAST(3.999 AS DECIMAL(10,2))实际是4.00(因为 DECIMAL 类型默认四舍五入)
PostgreSQL 的 TRUNCATE() 不四舍五入,但要注意数据类型推导
PostgreSQL 的 TRUNCATE(numeric, int) 真正按位截断,不进位,也不受 ROUND() 规则影响。但它对输入类型敏感:如果传入 float8(double precision),可能因浮点误差导致意外结果。
- 推荐显式转成
NUMERIC:TRUNCATE(3.141599999999999::NUMERIC, 3)→3.141 - 避免直接用浮点字面量:
TRUNCATE(3.141599999999999, 3)可能返回3.142(因底层二进制表示偏差) - 小数位数为负数时有效:
TRUNCATE(1234.56, -2)→1200.00(向左截断百位)
跨数据库兼容写法:用 ROUND() 模拟截断(慎用)
如果必须兼容 MySQL/PostgreSQL/SQL Server,又不想写条件分支,有人用 ROUND(x - SIGN(x)*0.5*POWER(10,-d), d) 模拟截断。但太绕,且 SIGN() 在 SQLite 里不支持,POWER() 在某些旧版 MySQL 里也没实现。
- 更稳妥的做法是:应用层截断(比如 Python 用
int(x * 10**n) / 10**n),尤其当精度要求严格时 - 如果非要在 SQL 层统一,优先用
CAST(... AS DECIMAL(p,s))并接受它「四舍五入」的行为——多数业务场景中,用户其实不区分「截断」和「四舍五入」,只是不想看到超长小数 - 千万别在金额计算中用浮点字段(如
FLOAT)做截断,0.1 + 0.2 != 0.3的问题会让TRUNCATE结果不可控
事情说清了就结束。真正麻烦的不是函数怎么写,而是你查文档时没注意当前数据库里 TRUNCATE 到底指哪件事。

















