truncate(x, d) 是 mysql 数值截断函数,不四舍五入,仅按位数直接丢弃多余数字:d>0 保留小数点后 d 位,d=0 去小数部分得整数,d<0 向高位归零;与 round(四舍五入)、format(字符串格式化且四舍五入)语义严格不同。

TRUNCATE(x, d) 的基本行为:不四舍五入,只砍掉多余位
MySQL 的 TRUNCATE() 函数不是“四舍五入”,而是严格按位数截断:从左往右数到小数点后第 d 位,之后所有数字直接丢弃,不进位、不补零、不调整原值精度。比如 TRUNCATE(9.999, 1) 得到 9.9,不是 10.0,也不是 9.90。
常见错误是把它和 ROUND() 混用,结果发现数值“变小了却没预期 rounding 效果”——这是设计如此,不是 bug。
-
d为正数(如2):保留小数点后d位,如TRUNCATE(123.4567, 2)→123.45 -
d为 0:直接去掉全部小数部分,返回整数,如TRUNCATE(123.4567, 0)→123 -
d为负数(如-1):向整数高位截断,TRUNCATE(123.45, -1)→120(个位归零),TRUNCATE(123.45, -3)→0 - 若
x或d为NULL,结果恒为NULL,不报错但需在业务逻辑中提前判断
和 ROUND()、FORMAT() 的关键区别在哪
三者都涉及小数位控制,但语义完全不同:
-
ROUND(x, d):先四舍五入再返回,ROUND(2.555, 2)→2.56;它可能改变整数部分(如ROUND(9.99, 0)→10) -
TRUNCATE(x, d):纯位数截断,TRUNCATE(2.555, 2)→2.55;永远不会进位,也不会增加小数位数 -
FORMAT(x, d):返回的是字符串(不是数字!),带千分位逗号且强制四舍五入,FORMAT(1234.567, 1)→'1,234.6';不能用于后续数值计算
如果你要导出报表时“显示两位小数但不进位”,用 TRUNCATE();如果要“金额四舍五入到分”,必须用 ROUND();如果只是前端展示格式化,FORMAT() 可能更省事,但别拿它做 where 条件或 join 字段。
DECIMAL 字段里用 TRUNCATE() 还需要注意什么
当源字段是 DECIMAL(m,n)(比如 DECIMAL(10,4)),调用 TRUNCATE(col, 2) 后,结果仍是数字类型,但精度由函数决定,不再受原列定义约束。这意味着:
- 不会自动补零:原值
10.0000经TRUNCATE(10.0000, 2)得10.00?错,实际得10(因为 MySQL 内部标准化去除了尾随零) - 想保留固定小数位显示(如始终显示两位),得配合
CAST(... AS DECIMAL(10,2))或应用层处理,TRUNCATE()本身不负责格式对齐 - 在 GROUP BY 或 ORDER BY 中使用
TRUNCATE(col, d),要注意它会改变值的分布粒度,可能导致原本不同的值被归为同一组(例如TRUNCATE(1.999, 0)和TRUNCATE(1.001, 0)都是1)
其他数据库里没有 TRUNCATE() 怎么办
MySQL 独有的 TRUNCATE(x,d) 在 PostgreSQL、SQL Server、Oracle 中并不存在(注意:SQL Server 的 TRUNCATE TABLE 是删表命令,和数值函数无关)。跨库兼容时常用替代方案:
- PostgreSQL:用
TRUNC(x, d)(函数名同名但语法一致,可直接替换) - SQL Server:用
ROUND(x, d, 1),第三个参数1表示截断而非四舍五入 - Oracle:用
TRUNC(x, d)(也是同名,行为一致) - 通用兜底(如 SQLite):
CAST(x * POWER(10,d) AS INTEGER) / POWER(10,d),但要注意浮点精度误差,尤其对DOUBLE值不安全
最易踩的坑是误以为所有 SQL 方言都有 TRUNCATE() 数值函数,上线前务必确认目标数据库支持情况;生产环境混用时,建议封装成视图或中间层函数统一处理。










